2

私はこのテーブルを持っています:

CREATE TABLE Category
(
  LogId int NULL,
  Name varchar(30) NOT NULL
)

LogIdsが異なる2つのカテゴリは同じNameである可能性がありますが、カテゴリの名前がnullのカテゴリと同じでない場合がありますLogId

この制約を適用する方法はありますか?

このビューで一意のインデックスを作成してみました。

create view Category_LogId_Name
  with schemabinding
as
select
  LogId,
  Name
from
  dbo.Category
where
  LogId is null
union all 
select
  b.LogId,
  a.Name
from
  dbo.Category a
  cross join dbo.Log b
where
  a.LogId is null

しかし、インデックスを作成しようとしています:

create unique clustered index un_Category_LogId_Name on Category_LogId_Name (LogId, Name)

このエラーが発生します:

ビュー'Category_LogId_Name'にインデックスを作成できません。これには、1つ以上のUNION、INTERSECT、またはEXCEPT演算子が含まれているためです。元のビューのUNION、INTERSECT、またはEXCEPT演算子への入力である、クエリごとに個別のインデックス付きビューを作成することを検討してください。

別のアプローチはありますか?

4

1 に答える 1

3

私があなたを正しく読んでいるなら、あなたには2つの制約があります:

  1. カテゴリ名 + LogId は一意である必要があります。LogId が null の場合、Name は一意である必要があります。
  2. 特定のカテゴリ名は、null 以外の LogId または null LogId に関連付けることができますが、両方には関連付けることはできません。

UNIQUE次のように、バニラの制約で (1) を強制します。

alter table dbo.Category add constraint UQ_Category (Name, LogId)

制約とは異なりPRIMARY KEYUNIQUE制約は 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 つの行があり、制約に違反します。

于 2012-12-18T03:18:17.667 に答える