SQL Server 2005 を使用しています。
一意の値または NULL 値のいずれかを含める必要があるフィールドがあります。CHECK CONSTRAINT
これを aまたは aで強制する必要があると思いますTRIGGER for INSERT, UPDATE
。
ここでトリガーよりも制約を使用する利点はありますか (またはその逆)? そのような制約/トリガーはどのように見えるでしょうか?
または、私が考慮していない別のより適切なオプションはありますか?
SQL Server 2005 を使用しています。
一意の値または NULL 値のいずれかを含める必要があるフィールドがあります。CHECK CONSTRAINT
これを aまたは aで強制する必要があると思いますTRIGGER for INSERT, UPDATE
。
ここでトリガーよりも制約を使用する利点はありますか (またはその逆)? そのような制約/トリガーはどのように見えるでしょうか?
または、私が考慮していない別のより適切なオプションはありますか?
where句を介してnullを無視するインデックスを使用してビューを作成します...つまり、テーブルにnullを挿入してもビューは気にしませんが、null以外の値を挿入すると、ビューは制約を適用します。
create view dbo.UniqueAssetTag with schemabinding
as
select asset_tag
from dbo.equipment
where asset_tag is not null
GO
create unique clustered index ix_UniqueAssetTag
on UniqueAssetTag(asset_tag)
GO
したがって、私の機器テーブルには、複数の null を許可するが一意の非 null 値のみを許可する asset_tag 列があります。
注: mssql 2000 を使用している場合は、テーブルに対して挿入、更新、または削除を実行する直前に、 " SET ARITHABORT ON " を実行する必要があります。これは mssql 2005 以降では必要ありません。
これは、制約を使用してそれを行う別の方法です。この制約を適用するには、フィールド値の出現回数をカウントする関数が必要です。制約では、この最大値が 1 であることを確認してください。
制約:
field is null or dbo.fn_count_maximum_of_field(field) < 2
編集私は今思い出せません-そしてそれをチェックすることもできません-挿入/更新の前または後に制約チェックが行われたかどうか。失敗時に挿入/更新がロールバックされた後だと思います。私が間違っていることが判明した場合、上記の 2 は 1 になるはずです。
テーブル関数は int を返し、次の選択を使用してそれを導出します
declare @retVal int
select @retVal = max(occurrences)
from (
select field, count(*) as occurrences
from dbo.tbl
where field = @field
group by field
) tmp
列が(一意ではない)インデックスである場合、これはかなり高速です。
これを実現するには、計算列を作成し、その列に一意のインデックスを配置します。
ALTER TABLE MYTABLE
ADD COL2 AS (CASE WHEN COL1 IS NULL THEN CAST(ID AS NVARCHAR(255)) ELSE COL1 END)
CREATE UNIQUE INDEX UQ_COL2 ON MYTABLE (COL2)
これは、ID がテーブルの PK であり、COL1 が「一意または null」の列であると想定しています。
「一意の」列が null の場合、計算列 (COL2) は PK の値を使用します。
次の例では、ID 列と COL1 の間で競合が発生する可能性があります。
ID COL1 COL2
1 [NULL] 1
2 1 1
これを回避するために、通常、COL2 の値が ID 列または COL1 列のどちらから取得されたかを格納する別の計算列を作成します。
ALTER TABLE MYTABLE
ADD COL3 AS (CASE WHEN COL1 IS NULL THEN 1 ELSE 0 END)
インデックスは次のように変更する必要があります。
CREATE UNIQUE INDEX UQ_COL2 ON MYTABLE (COL2, COL3)
現在、インデックスは計算列 COL2 と COL3 の両方にあるため、問題はありません。
ID COL1 COL2 COL3
1 [NULL] 1 1
2 1 1 0
このテーブルに主キー、おそらく ID 列はありますか? 主キーと組み合わせて一意性を強制するフィールドの複合である一意のキーを作成できます。
ここでこの種の問題についての議論があります: http://blog.sqlauthority.com/2008/09/07/sql-server-explanation-about-usage-of-unique-index-and-unique-constraint/
参考までに - SQL Server 2008 ではフィルター選択されたインデックスが導入されているため、これに少し異なる方法でアプローチできます。
Oracle では、一意のキーは複数の NULL を許可します。
SQL Server 2005 では、ビューを介して挿入を行い、テーブルへの直接挿入を無効にすることをお勧めします。
通常、トリガーを使用すると、チェック制約よりも詳細で説明的なメッセージを提供できるため、これらを使用して、デバッグ時に「どの列が悪いか」というゲームを回避しました。
一意の制約は実質的にはインデックスですが、制約はトリガーよりもはるかに軽量です。
ただし、一意の制約/インデックスで許可される NULL は 1 つだけです。そのため、トリガーを使用して重複を検出する必要があります。
MS から NULLS を無視するように要求されましたが、SQL 2008 ではインデックスがフィルター処理されています (これを入力しているときに述べたように)