私があなたを正しく読んでいるなら、あなたには2つの制約があります:
- カテゴリ名 + LogId は一意である必要があります。LogId が null の場合、Name は一意である必要があります。
- 特定のカテゴリ名は、null 以外の LogId または null LogId に関連付けることができますが、両方には関連付けることはできません。
UNIQUE
次のように、バニラの制約で (1) を強制します。
alter table dbo.Category add constraint UQ_Category (Name, LogId)
制約とは異なりPRIMARY KEY
、UNIQUE
制約は null 許容キーを許可し、null を同じ「値」のインスタンスとして扱います。したがって、次のデータが許可されます。
insert dbo.Category (LogId, Name) values (null, 'Name1') -- ok
insert dbo.Category (LogId, Name) values (1, 'Name1') -- ok
insert dbo.Category (LogId, Name) values (2, 'Name1') -- ok
insert dbo.Category (LogId, Name) values (3, 'Name1') -- ok
しかし、これは最初の挿入後に拒否されます:
insert dbo.Category (LogId, Name) values (null, 'Name1') -- ok
insert dbo.Category (LogId, Name) values (null, 'Name1') -- error
insert dbo.Category (LogId, Name) values (null, 'Name1') -- error
insert dbo.Category (LogId, Name) values (null, 'Name1') -- error
次に (2) の場合、名前が null の LogId に関連付けられている場合、null 以外の LogId に関連付けることができず、その逆も成り立つように、排他性を強制する何かが必要です。このために、インデックス付きビューで Name と LogId の nullity でグループ化します。
create view dbo.MakeItExclusive
with schemabinding as
select Name
, case when LogId is null then 1 else 0 end as HasNullLogIds
, count_big(*) as _rowcount
from dbo.Category
group by Name
, case when LogId is null then 1 else 0 end
go
create unique clustered index CU_MakeItExclusive on dbo.MakeItExclusive (Name)
go
ビューにはGROUP BY
句があるため、SQL Server は句でインデックスを作成する必要COUNT_BIG(*)
があります。SELECT
それを超えて、それは非常に簡単です: Name と LogId-nullness でグループ化し、Name が結果で一意であることを確認します。Name が null の LogId と null 以外の LogId の両方に関連付けられている場合、2 つの行があり、制約に違反します。