SQLで条件付きのnot null制約を作成することは可能ですか? 言い換えれば、長い列 A が含まれている限り列 B を null にすることができるような制約を作成することは可能ですが、列 A の内容が別のものに変更された場合、列 B を null にすることはできなくなりますか?
そしてそれを拡張するために、列Aが「NEW」である限り、列Bがnullまたは空でなければならないようにすることができますか?
ありがとうございました:D
4 に答える
これは、CONSTRAINT CHECK ではまったく問題ありません。これを行うだけです:
要件:
長い列Aが含まれているので、列Bがnullになることができるような制約を作成することは可能ですか?
フレーズに注意してください: 列 Bは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
)
);
最初に述べた要件は次のとおりだと思います。
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 )
編集:他の回答で述べたように、最初に提案したトリガーではなく、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)'
);
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
クエリでは、テーブルのように動作する特別なオブジェクトであるinsertを参照する必要があることに注意してください。これにより、トリガーの原因となった行を参照できます。
もちろん、この例では、制約を適用するためにAFTER UPDATEも処理する必要がありますが、それが一般的な考え方です。