SQLで条件付きの非NULL制約を作成できるかどうか知りたいのですが。言い換えると、列Aに「NEW」と表示されている限り列Bがnullになるような制約を作成できますが、列Aの内容が別のものに変更された場合、列Bはnullになりませんか?
さらに拡張すると、列Aが「NEW」と表示されている限り、列Bがnullまたは空になるようにすることができますか?
ありがとうございました:D
これは、制約チェックにはまったく問題ありません。これを行うだけです:
要件:
列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
)
);
編集:他の回答で述べたように、私が最初に提案したトリガーではなく、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)'
);
最初に述べた要件は次のとおりです。
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 )
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を処理する必要がありますが、これが一般的な考え方です。