3つの列のうち1つだけがNULLでないチェック制約


61

FLOAT、NVARCHAR(30)、またはDATETIME(3つの独立した列)の3種類の結果を含む(SQL Server)テーブルがあります。特定の行について、1つの列のみが結果を持ち、他の列がNULLであることを確認したい。これを達成するための最も単純なチェック制約は何ですか?

このコンテキストは、非数値の結果を既存のシステムに取り込む機能を改良しようとしています。行ごとに複数の結果を防ぐために2つの新しい列を制約付きでテーブルに追加することが最も経済的なアプローチであり、必ずしも正しいものではありません。

更新:申し訳ありませんが、データ型はsnafuです。悲しいことに、示された結果の型をSQL Serverのデータ型として解釈するつもりはなく、単に一般的な用語が修正されました。

回答:


72

以下はトリックを実行する必要があります。

CREATE TABLE MyTable (col1 FLOAT NULL, col2 NVARCHAR(30) NULL, col3 DATETIME NULL);
GO

ALTER TABLE MyTable
ADD CONSTRAINT CheckOnlyOneColumnIsNull
CHECK 
(
    ( CASE WHEN col1 IS NULL THEN 0 ELSE 1 END
    + CASE WHEN col2 IS NULL THEN 0 ELSE 1 END
    + CASE WHEN col3 IS NULL THEN 0 ELSE 1 END
    ) = 1
)
GO

24

おそらく、制約内で3つのテストを実行する必要があります。1つはnullにするペアごとに、もう1つはNULL以外の列に対してテストします。

ALTER TABLE table
ADD CONSTRAINT CK_one_is_null
CHECK (
     (col1 IS NOT NULL AND col2 IS NULL AND col3 IS NULL)
  OR (col2 IS NOT NULL AND col1 IS NULL AND col3 IS NULL) 
  OR (col3 IS NOT NULL AND col1 IS NULL AND col2 IS NULL)
);

これはそれほどスケーラブルではありません。9つの外部キーを持つテーブルがあり、1つだけがnullであってはなりません。@ MarkStoreySmithのソリューションを好む
Amir

5

以下は、組み込みの配列関数を使用したPostgreSQLソリューションです

ALTER TABLE your_table
ADD chk_only_one_is_not_null CHECK (array_length(array_remove(ARRAY[col1::text, col2::text, col3::text], NULL), 1) = 1);

これは、前述のMark Storeyとmrdennyがそれぞれ投稿したCASEまたはAND / ORソリューションよりもpostgreSQLでの実装が高速ですか?
クリスブリット
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.