私の開発者は、テーブルに配置されたチェック制約でこれを達成できると主張しています。
SQL Server は、制約内のサブクエリを直接サポートしません** CHECK
(完全な SQL-92 の要件です。SQL Server は、大まかに言えば、エントリー レベルの SQL-92 のみに準拠しています)。
SQL Server でこの制約を強制するより良い方法がほぼ確実に存在しますが、純粋に興味深いことに、実際には行レベルのCHECK
制約と制約を使用して実現できUNIQUE
ます。たとえば、次の 1 つの方法があります。
CREATE TABLE YourStuff
(
key_col INTEGER NOT NULL UNIQUE,
Various_Columns VARCHAR(8) NOT NULL,
Flag CHAR(1) DEFAULT 'F' NOT NULL
CHECK (Flag IN ('F', 'T')),
Flag_key INTEGER UNIQUE,
CHECK (
(Flag = 'F' AND Flag_key = key_col)
OR
(Flag = 'T' AND Flag_key = NULL)
)
);
ここでの問題は、Flag_key
列の値を「手動で」維持する必要があることです。列 +CHECK
を計算列に置き換えると、値が自動的に維持されることを意味します。
CREATE TABLE YourStuff
(
key_col INTEGER NOT NULL UNIQUE,
Various_Columns VARCHAR(8) NOT NULL,
Flag CHAR(1) DEFAULT 'F' NOT NULL
CHECK (Flag IN ('F', 'T')),
Flag_key AS (
CASE WHEN Flag = 'F' THEN key_col
ELSE NULL END
),
UNIQUE (Flag_key)
);
** SQL Server は制約内のサブクエリを直接サポートしていませんが、場合によってはユーザー定義関数 (UDF) を使用する回避策があります。CHECK
CREATE FUNCTION dbo.CountTFlags ()
RETURNS INTEGER
AS
BEGIN
DECLARE @return INTEGER;
SET @return = (
SELECT COUNT(*)
FROM YourStuff
WHERE Flag = 'T'
);
RETURN @return;
END;
CREATE TABLE YourStuff
(
key_col INTEGER NOT NULL UNIQUE,
Various_Columns VARCHAR(8) NOT NULL,
Flag CHAR(1) DEFAULT 'F' NOT NULL
CHECK (Flag IN ('F', 'T')),
CHECK (1 >= dbo.CountTFlags())
);
UDF アプローチがすべての場合に機能するとは限らず、注意が必要であることに注意してください。重要な点は、影響を受ける行ごとに UDF が評価されることです (ご想像のとおり、SQL ステートメントまたはトランザクション レベルではなく)。この場合、影響を受けるすべての行に対して制約が真である必要があるため、--と思います! - 安全。詳細については、David Portas による Trouble with CHECK Constraints を参照してください。
個人的には、モデル化するために2番目のテーブルを使用するFlag
だけで、キーと外部キーのみが含まれます。
CREATE TABLE YourStuff
(
key_col INTEGER NOT NULL UNIQUE,
Various_Columns VARCHAR(8) NOT NULL
);
CREATE TABLE YourStuffFlag
(
key_col INTEGER NOT NULL UNIQUE
REFERENCES YourStuff (key_col)
);
[my] テーブルは通常の形式ですか?
目指すべきはフィフスノーマルフォーム(5NF)。これを達成できるかどうかは、 の設計に依存しますVarious_Columns
。あなたFlag
が 5NF の要件を満たしているとは思えず、更新、削除、または挿入の異常も見られません (これは正規化のポイントですが、5NF 設計は依然として異常を示す可能性があります)。とはいえ、属性を取得する行を切り替えるにはflag
、私の 2 テーブルの設計では 1 つのUPDATE
ステートメントが必要ですが、1 つのテーブルの設計では 2 つのステートメントが必要です ;)