web-dev-qa-db-ja.com

3つの列のうち1つだけがnullでないことを確認する

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

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

更新:申し訳ありませんが、データ型はsnafuです。残念なことに、表示されている結果の型がSQL Serverのデータ型として解釈されるようには意図されていませんでした。

65
David Clarke

次はトリックをするべきです:

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
78

おそらく、制約内で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)
);
24
mrdenny

組み込みの配列関数 を使用した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);
5
CrEOF

POSTGRESQLの場合

CHECK( (col_1 IS NOT NULL)::integer + (col_2 IS NOT NULL)::integer + ... = 1 )

列をbooleanに変換しますIS NOT NULLtrueまたはfalse)、次に:: integer(または1)次に算術演算子を使用できます

= 1  //must one row is not null  
<= 1 //only one row can be not null
1
Mendes