sql >> データベース >  >> RDS >> Sqlserver

SQLServerでCHECK制約を有効にする場合のWITHNOCHECKについて知っておくべきこと

    CHECKを再度有効にする必要がある状況に陥った場合 以前に無効にされた制約については、自分が何をしているのかを確実に理解する必要があります。

    特に、WITH NOCHECKの違いを理解する必要があります およびWITH CHECK 引数。

    これらの引数は、制約を有効にするときに使用できます。これらは、既存のデータが再度有効にされた(または新しく追加された)CHECKに対して検証されるかどうかを指定します 制約。基本的に、制約に対する違反がないか、既存のすべてのデータをチェックするオプションがあります。何も指定しない場合、既存のデータはありません チェックされます。そのため、それがどのように機能するかを理解することが重要です。

    ちなみに、これらの引数は外部キー制約にも適用されます。

    ご想像のとおり、WITH CHECK 既存のデータが検証され、WITH NOCHECKであることを指定します そうでないことを指定します。デフォルトはWITH NOCHECK

    WITH NOCHECKを使用する場合 、制約は信頼できないものとしてフラグが立てられます。実際、制約を無効にすると、信頼できないというフラグが立てられます。ただし、再度有効にすると、WITH CHECKを使用しない限り、信頼されないままになります。 。つまり、その「信頼性」を言い換える場合は、これを明示的に指定する必要があります。

    言い換えれば:

    • WITH NOCHECKを使用する場合 、制約は信頼されないままになります。
    • WITH CHECKを使用する場合 信頼できるようになりますが、既存のすべてのデータが制約に準拠している場合に限ります。既存のデータが制約に違反している場合、制約は有効にならず、エラーメッセージが表示されます。

    もちろん、「既存のすべてのデータ」と言うときは、制約が適用されるデータのみを指します。

    制約に違反するデータを入力しなければならなかったために、意図的に制約を無効にしたシナリオがあるかもしれません。このような場合、無効なデータをデータベースに残す必要がある場合は、WITH NOCHECKを使用する必要があります。 制約を再度有効にする場合。これにより、既存のデータを邪魔することなく制約を有効にできます。

    以下はこれを示す例です。

    例1-チェック制約の確認

    まず、sys.check_constraintsを使用しましょう すべてのCHECKを確認します 現在のデータベースの制約。

    SELECT 
      name,
      is_disabled,
      is_not_trusted,
      definition
    FROM sys.check_constraints;
    

    結果:

    +-----------------+---------------+------------------+----------------------------------------+
    | name            | is_disabled   | is_not_trusted   | definition                             |
    |-----------------+---------------+------------------+----------------------------------------|
    | chkPrice        | 0             | 0                | ([Price]>(0))                          |
    | chkValidEndDate | 0             | 0                | ([EndDate]>=[StartDate])               |
    | chkTeamSize     | 0             | 0                | ([TeamSize]>=(5) AND [TeamSize]<=(20)) |
    | chkJobTitle     | 0             | 0                | ([JobTitle]<>'Digital Nomad')          |
    +-----------------+---------------+------------------+----------------------------------------+
    

    それらがすべて有効で信頼されていることがわかります( is_disabled にすべてゼロがあるため) および is_not_trusted 列)。

    この記事では、 chkJobTitle を無効にしてから再度有効にします。 制約。

    例2–制約を無効にする

    ここでは、 chkJobTitle を無効にします 制約:

    ALTER TABLE Occupation  
    NOCHECK CONSTRAINT chkJobTitle; 
    

    完了しました。

    それでは、すべての制約をもう一度確認しましょう:

    SELECT 
      name,
      is_disabled,
      is_not_trusted,
      definition
    FROM sys.check_constraints;
    

    結果:

    +-----------------+---------------+------------------+----------------------------------------+
    | name            | is_disabled   | is_not_trusted   | definition                             |
    |-----------------+---------------+------------------+----------------------------------------|
    | chkPrice        | 0             | 0                | ([Price]>(0))                          |
    | chkValidEndDate | 0             | 0                | ([EndDate]>=[StartDate])               |
    | chkTeamSize     | 0             | 0                | ([TeamSize]>=(5) AND [TeamSize]<=(20)) |
    | chkJobTitle     | 1             | 1                | ([JobTitle]<>'Digital Nomad')          |
    +-----------------+---------------+------------------+----------------------------------------+
    

    無効になっていることがわかります( is_disabled が原因) 列が 1 に設定されている 。

    is_not_trusted に気付くかもしれません 列も 1 に設定されます 。これは、CHECKが 制約は、すべての行についてシステムによって検証されていません。

    前述のように、CHECK 制約は、すべてのデータが制約の条件を正常に通過した場合にのみ信頼できます。制約を無効にすると、無効なデータがデータベースに入る可能性があります。したがって、すべてのデータが有効であると100%確信できるわけではないため、制約には信頼できないというフラグが立てられます。

    制約が再び信頼されるようにする方法は、WITH CHECKを使用して制約を再度有効にすることです。 口論。これにより、制約は、データが再度有効になる前にすべてのデータをチェックします。無効なデータがある場合、そのデータを再度有効にすることはできません。有効になるようにデータを更新するか、WITH NOCHECKを使用して制約を再度有効にする必要があります 代わりに引数(これにより、制約が信頼できないままになります)。

    例3–デフォルト設定(NOCHECKを使用)を使用して制約を有効にする

    制約を再度有効にして、クエリを再度実行してみましょう。

    制約を有効にするために、私は怠惰になり、デフォルト設定を使用します:

    ALTER TABLE Occupation  
    CHECK CONSTRAINT chkJobTitle; 
    

    次に、変更を確認します:

    SELECT 
      name,
      is_disabled,
      is_not_trusted,
      definition
    FROM sys.check_constraints;
    

    結果:

    +-----------------+---------------+------------------+----------------------------------------+
    | name            | is_disabled   | is_not_trusted   | definition                             |
    |-----------------+---------------+------------------+----------------------------------------|
    | chkPrice        | 0             | 0                | ([Price]>(0))                          |
    | chkValidEndDate | 0             | 0                | ([EndDate]>=[StartDate])               |
    | chkTeamSize     | 0             | 0                | ([TeamSize]>=(5) AND [TeamSize]<=(20)) |
    | chkJobTitle     | 0             | 1                | ([JobTitle]<>'Digital Nomad')          |
    +-----------------+---------------+------------------+----------------------------------------+
    

    何が起こったのかわかりましたか?制約を再度有効にしましたが、それでも信頼されていません。

    これは、制約を有効にしたときに怠惰だった(または単に忘れていた)ためです。制約を有効にしたときに、WITH CHECKを指定するのを忘れました 。デフォルトはWITH NOCHECK これは、制約を再度有効にするときに既存のデータがチェックされないことを意味します。

    これが、CHECKを有効にするときに何をしているのかを確実に知っておく必要がある理由です。 (およびFOREIGN KEY )制約。怠惰で、潜在的に重要な設定を明示的に指定しないことにより、SQLServerに既存のデータの問題に目をつぶる許可を与えます。

    ただし、制約を無効にする必要がある理由全体が制約に違反するデータを挿入することである場合は、デフォルトのWITH NOCHECK おそらくあなたが望むものです。

    ちなみに、新しい制約の場合、デフォルトはWITH CHECKです。 。

    しかし、私の場合、を挿入または更新しませんでした 制約を無効にした後のデータなので、以前は信頼できたとしても、今でも信頼できるはずです。

    では、どうすれば制約を再び信頼できるようになりますか?

    例4–WITHCHECKを使用して制約を有効にする

    制約を再度信頼できるようにする場合は、WITH CHECKを明示的に指定する必要があります。 再度有効にするとき。

    もう一度制約を無効にしましょう:

    ALTER TABLE Occupation  
    NOCHECK CONSTRAINT chkJobTitle; 
    

    これで、再度有効にする前の状態に戻りました。

    再度有効にしたときにすべきだったのは、次のとおりです。

    ALTER TABLE Occupation  
    WITH CHECK CHECK CONSTRAINT chkJobTitle; 
    

    次に、制約をもう一度見てください。

    SELECT 
      name,
      is_disabled,
      is_not_trusted,
      definition
    FROM sys.check_constraints;
    

    結果:

    +-----------------+---------------+------------------+----------------------------------------+
    | name            | is_disabled   | is_not_trusted   | definition                             |
    |-----------------+---------------+------------------+----------------------------------------|
    | chkPrice        | 0             | 0                | ([Price]>(0))                          |
    | chkValidEndDate | 0             | 0                | ([EndDate]>=[StartDate])               |
    | chkTeamSize     | 0             | 0                | ([TeamSize]>=(5) AND [TeamSize]<=(20)) |
    | chkJobTitle     | 0             | 0                | ([JobTitle]<>'Digital Nomad')          |
    +-----------------+---------------+------------------+----------------------------------------+
    

    ふぅ!私の制約はもう一度信頼できます。

    例5–無効なデータでチェック制約を有効にする

    もちろん、無効になっているときに無効なデータを挿入しなかったため、制約は再び信頼されるだけです。これを行った場合、WITH CHECKを使用して有効にすることはできません。 、以下に示すように。

    もう一度無効にした場合:

    ALTER TABLE Occupation  
    NOCHECK CONSTRAINT chkJobTitle; 
    

    次に、無効なデータを挿入します(そして結果を返します):

    INSERT INTO Occupation
    VALUES ( 7, 'Digital Nomad' );
    
    SELECT 
      OccupationId,
      JobTitle
    FROM Occupation;
    

    結果:

    +----------------+-----------------+
    | OccupationId   | JobTitle        |
    |----------------+-----------------|
    | 1              | Engineer        |
    | 2              | Accountant      |
    | 3              | Cleaner         |
    | 4              | Attorney        |
    | 5              | Sales Executive |
    | 6              | Uber Driver     |
    | 7              | Digital Nomad   |
    +----------------+-----------------+
    

    そのため、無効なデータ(最後の行)を正常に挿入しました。

    制約の定義が次のようになるため、これは無効です:([JobTitle]<>'Digital Nomad')

    これは、 JobTitle が 列にDigital Nomadというテキストを含めることはできません 。

    それでは、CHECKを再度有効にしてみましょう。 WITH CHECKを使用した制約 何が起こるか見てみましょう。

    ALTER TABLE Occupation  
    WITH CHECK CHECK CONSTRAINT chkJobTitle; 
    

    結果:

    Msg 547, Level 16, State 0, Line 1
    The ALTER TABLE statement conflicted with the CHECK constraint "chkJobTitle". The conflict occurred in database "Test", table "dbo.Occupation", column 'JobTitle'.
    

    そのため、WITH CHECKを使用して制約を再度有効にすることはできません。 CHECKに違反するデータがテーブルにあります 制約。データを更新するか、WITH NOCHECKを使用する必要があります (または単に完全に省略します。)

    WITH NOCHECKを使用してもう一度試してみましょう 。

    ALTER TABLE Occupation  
    WITH NOCHECK CHECK CONSTRAINT chkJobTitle; 
    

    結果:

    Commands completed successfully.
    Total execution time: 00:00:00.015
    

    したがって、既存のデータをチェックしなくても、制約を正常に有効にできます。

    もちろん、この場合はCHECK 制約はまだ信頼されていません。制約を信頼できるようにする場合は、制約に違反しないようにデータを更新する必要があります。

    例:

    UPDATE Occupation
    SET JobTitle = 'Unemployed'
    WHERE OccupationId = 7;
    
    SELECT 
      OccupationId,
      JobTitle
    FROM Occupation;
    

    結果:

    +----------------+-----------------+
    | OccupationId   | JobTitle        |
    |----------------+-----------------|
    | 1              | Engineer        |
    | 2              | Accountant      |
    | 3              | Cleaner         |
    | 4              | Attorney        |
    | 5              | Sales Executive |
    | 6              | Uber Driver     |
    | 7              | Unemployed      |
    +----------------+-----------------+
    

    これで、CHECKを変更できます 再び信頼されるようになるための制約。

    3つすべてを一緒にしましょう:

    ALTER TABLE Occupation  
    NOCHECK CONSTRAINT chkJobTitle; 
    
    ALTER TABLE Occupation  
    WITH CHECK CHECK CONSTRAINT chkJobTitle; 
    
    SELECT 
      name,
      is_disabled,
      is_not_trusted,
      definition
    FROM sys.check_constraints;
    

    結果:

    +-----------------+---------------+------------------+----------------------------------------+
    | name            | is_disabled   | is_not_trusted   | definition                             |
    |-----------------+---------------+------------------+----------------------------------------|
    | chkPrice        | 0             | 0                | ([Price]>(0))                          |
    | chkValidEndDate | 0             | 0                | ([EndDate]>=[StartDate])               |
    | chkTeamSize     | 0             | 0                | ([TeamSize]>=(5) AND [TeamSize]<=(20)) |
    | chkJobTitle     | 0             | 0                | ([JobTitle]<>'Digital Nomad')          |
    +-----------------+---------------+------------------+----------------------------------------+
    

    これで、制約が有効になり、信頼できるようになりました。データベースにはデジタル遊牧民がいません!


    1. ウェイトイベントを見つける方法Oracleセッションの履歴

    2. PythonインポートMySQLdbエラー-Mac10.6

    3. 別のテーブルのフィールドから1つのテーブルのSQL更新フィールド

    4. MariaDBでのCOT()のしくみ