SQL Server の制約についてサポートが必要です。この状況は、テーブルの各 OrderID=1 (主キーではなく外部キーであるため、同じ ID を持つ複数の行がある) であり、ビット フィールドはそれらの行の 1 つに対してのみ 1 であり、OrderID=2 の各行に対して、ビット フィールドは 1 つの行に対してのみ 1 にすることができます。同じ OrderID を持つ他のすべての行に対しては 0 にする必要があります。ビット フィールドが 1 に設定されている OrderID を持つ行が既に存在する場合、ビット フィールドに 1 が含まれる新しいレコードはすべて拒否する必要があります。何かアイデアはありますか?
4 に答える
CREATE UNIQUE INDEX ON UnnamedTable (OrderID) WHERE UnnamedBitField=1
これはFiltered Indexと呼ばれます。2008 年より前のバージョンの SQL Server を使用している場合は、インデックス付きビューを使用して、フィルター処理されたインデックスに相当する簡易版を実装できます。
CREATE VIEW UnnamedView
WITH SCHEMABINDING
AS
SELECT OrderID From UnnamedSchema.UnnamedTable WHERE UnnamedBitField=1
GO
CREATE UNIQUE CLUSTERED INDEX ON UnnamedView (OrderID)
SQL Server は列の制約と行の制約しかサポートしていないため、実際には制約として行うことはできません。テーブル内のすべての値を処理する制約を記述する (偽りのない) 方法はありません。
スキーマをより完全に正規化することができます。これにより、既に設定されているビットを探す必要がなくなり、結合を使用することができます。ビット フィールドを削除し、OrderID とテーブルの主キーを含む X という新しいテーブルを作成する必要があります。X の主キーはこれらすべてのフィールドです。
これは、挿入するときに、元のテーブルと X f に挿入する必要があり、テーブルでビットを 1 に設定した場合にのみ必要であることを意味します。ビットが 1 に設定された元の行が既に存在するかのように、X に行が既に存在する場合、挿入は失敗します。
欠点は、これがスキーマよりも多くのスペースを占有することですが、ビットが 1 に設定された 2 つの行を持つことと同等にならないため、維持が容易です。
私は他の答えに同意します。スキーマを変更できる場合はそれを行いますが、そうでない場合は、このようなことができると思います。
CREATE FUNCTION fnMyCheck
(@id INT)
RETURNS INT
AS
BEGIN
DECLARE @i INT
SELECT @i = COUNT(*)
FROM MyTable
WHERE FkCol = @id
AND BitCol = 1
RETURN @i
END
ALTER TABLE YourTable
ADD CONSTRAINT ckMyCheck CHECK (fnMyCheck(FkCol)<=1)
しかし、このようなチェック制約で udf を使用すると、問題が発生する可能性があります。
この「ソリューション」の問題に関するコメントを追加するために編集します。
あなたがリンクしたものよりも簡単な問題があります。
INSERT INTO YourTable(FkCol,BitCol) VALUES (1,1),(1,0)
に続く
UPDATE YourTable SET BitCol=1
成功し、FkCol=1 および BitCol=1 の 2 つの行を残します