2

我有这张桌子:

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

具有不同LogIds 的两个类别可能具有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”上创建索引,因为它包含一个或多个 UNION、INTERSECT 或 EXCEPT 运算符。考虑为作为原始视图的 UNION、INTERSECT 或 EXCEPT 运算符的输入的每个查询创建单独的索引视图。

有不同的方法吗?

4

1 回答 1

3

如果我没看错,你有两个限制:

  1. Category Name + LogId 必须唯一;如果 LogId 为 null,则 Name 必须是唯一的。
  2. 给定的类别名称可能与非空 LogId 或空 LogId 相关联,但不能同时与两者相关联。

UNIQUE您使用香草约束强制执行 (1) ,如下所示:

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

PRIMARY KEY约束不同,UNIQUE约束允许可为空的键,并将空值视为相同“值”的实例。因此,将允许此数据:

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),您需要一些东西来强制执行排他性,这样如果 Name 与 null LogId 相关联,则它不能与非 null LogId 相关联,反之亦然。为此,您可以在索引视图中按名称和 LogId 的无效性进行分组:

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 在结果中是唯一的。如果名称与空 LogId 和非空 LogId 相关联,则会有两行违反约束。

于 2012-12-18T03:18:17.667 回答