web-dev-qa-db-ja.com

SQL条件付きNOTNULL制約


SQLで条件付きの非NULL制約を作成できるかどうか知りたいのですが。言い換えると、列Aに「NEW」と表示されている限り列Bがnullになるような制約を作成できますが、列Aの内容が別のものに変更された場合、列Bはnullになりませんか?
さらに拡張すると、列Aが「NEW」と表示されている限り、列Bがnullまたは空になるようにすることができますか?
ありがとうございました:D

24
Heinrich

これは、制約チェックにはまったく問題ありません。これを行うだけです:

要件:

列Aに「NEW」と表示されている限り、列Bがnullになるような制約を作成することはできますが、列Aの内容が別のものに変更された場合、列Bはnullになりませんか?

フレーズに注意してください:列B can null

解決:

create table tbl
(
    A varchar(10) not null,
    B varchar(10),

    constraint uk_tbl check
    (
      A = 'NEW' -- B can be null or not null: no need to add AND here
      OR (A <> 'NEW' AND B IS NOT NULL)
    )
);

あなたはそれをさらに単純化することができます:

create table tbl
(
    A varchar(10) not null,
    B varchar(10),

    constraint uk_tbl check
    (
      A = 'NEW' 
      OR B IS NOT NULL
    )
);

上記の要件と相互に互換性のない要件:

そしてそれを拡張するために、列Aが「NEW」と言っている限り、列Bがnullまたは空でなければならないようにすることができますか?

フレーズに注意してください:列B 必須 nullである

create table tbl
(
    A varchar(10) not null,
    B varchar(10),

    constraint uk_tbl check
    (
      (A = 'NEW' AND B IS NULL)
      OR A <> 'NEW'
    )
);

これで簡略化できますが、上記のように読みにくい場合があります。

create table tbl
(
    A varchar(10) not null,
    B varchar(10),

    constraint uk_tbl check
    (
      A <> 'NEW'
      OR B IS NULL
    )
);
30
Michael Buen

編集:他の回答で述べたように、私が最初に提案したトリガーではなく、CHECKが最良の方法です。元のテキストは次のとおりです。


Dbasemanが示唆するように、 トリガーは行く方法です (そうではありません)。このようなものを試してください(テストされていません):

CREATE OR REPLACE TRIGGER test
  BEFORE UPDATE ON table1
FOR EACH ROW
WHEN (new.A = 'NEW' and new.B IS NOT NULL)
   RAISE_APPLICATION_ERROR (
     num=> -20001,
     msg=> 'B must be NULL for new rows (A = NEW)'
);
1
dwurf

最初に述べた要件は次のとおりです。

IF ( B IS NULL ) THEN ( A = 'NEW' )

含意書き換えルールを適用します。

IF ( X ) THEN ( Y )   <=>   ( NOT ( X ) OR ( Y ) )

あなたの場合;

( NOT ( B IS NULL ) OR ( A = 'NEW' ) )

SQL構文を利用するためのマイナーな書き直し:

( B IS NOT NULL OR A = 'NEW' )

2番目に述べた(「拡張」)要件:

IF ( A = 'NEW' ) THEN ( B IS NULL )

書き換えルールを適用します。

( NOT ( A = 'NEW' ) OR ( B IS NULL ) )

マイナーな書き直し:

( A <> 'NEW' OR B IS NULL )
1
onedaywhen

onedaywhenによると、この答えは刑事的に間違っており、忌まわしいものです。 [〜#〜] check [〜#〜]制約を使用できます。 http://msdn.Microsoft.com/en-us/library/ms188258.aspx

条件付き制約を作成する方法はありません。ただし、トリガーを使用してジョブを実行できる必要があります。それが彼らの目的です。

http://msdn.Microsoft.com/en-us/library/ms189799.aspx

CREATE TRIGGER MyTable.ConditionalNullConstraint ON MyTable.ColumnB
AFTER INSERT
AS
IF EXISTS (SELECT *
    FROM inserted
    WHERE A <> 'NEW' AND B IS NULL
    )
BEGIN
    RAISERROR ('if A is ''NEW'' then B cannot be NULL', 16, 1);
    ROLLBACK TRANSACTION;
END;
GO

クエリでは、テーブルのように動作し、行を参照できる特別なオブジェクトであるinsertedを参照する必要があることに注意してください。それがトリガーを引き起こしました。

もちろん、この例では、制約を適用するためにもAFTER UPDATEを処理する必要がありますが、これが一般的な考え方です。

0
McGarnagle