似乎在SQL Server中,唯一索引将NULL视为“只是另一个值”,而不是在SQL的其余部分中将NULL与NULL的比较返回NULL。
假设您有一个表(t
)在可空列K
上有唯一索引:
K V
0 32
1 12
3 45
一切都很好。
但它也会允许
K V
0 32
1 12
3 45
NULL 89 <-- Baaad
反之亦然,它还允许以下内容:
K V
NULL 89
0 32 <-- not good
我可以看到这可能是一个潜在的灾难,因为我使用NULL键值表示不可能进一步分解的值 - 总计和分解会导致重复计算或不一致。
我可以找到数以千计的问题,其中人们想要做相反的事情(允许多个NULL),但没有人想要将NULL视为NULL。
如何让SQL Server在唯一索引中将NULL视为NULL(并且只允许列中的一个NULL 或任意数量的唯一值)?
答案 0 :(得分:1)
如果Andomar对您想要的内容的解释是正确的,那么如果您的表格已经包含所有可能的K
值,那么它可能是可行的:
create table dbo.T (
K int null,
V int not null,
)
go
create table dbo.PossibleKs (
K int not null
)
insert into dbo.PossibleKs (K) values (0),(1),(2)
go
create view dbo.TV
with schemabinding
as
select pk.K
from
dbo.T t
inner join
dbo.PossibleKs pk
on
t.K = pk.K or
t.K is null
GO
create unique clustered index IX_TV on dbo.TV (K)
您的测试用例:
insert into dbo.T(K,V) values
(0, 32),
(1, 12),
(3, 45)
go
insert into dbo.T(K,V) values
(NULL,89)
--Msg 2601, Level 14, State 1, Line 1
--Cannot insert duplicate key row in object 'dbo.TV' with unique index 'IX_TV'. The duplicate key value is (0).
--The statement has been terminated.
go
delete from dbo.T
go
insert into dbo.T(K,V) values
(NULL,89)
go
insert into dbo.T(K,V) values
(0, 32)
--Msg 2601, Level 14, State 1, Line 1
--Cannot insert duplicate key row in object 'dbo.TV' with unique index 'IX_TV'. The duplicate key value is (0).
--The statement has been terminated.
答案 1 :(得分:0)
因此,您需要一个null
或任意数量的唯一数字。我不认为可以使用约束来可靠地执行。
您可以使用触发器。触发器必须回答以下问题:您是否将行更新为null
?是否已经有一行null
?您是否正在更新已经null
的行?触发器将很复杂且难以维护。
您可以使用存储过程操作表。存储过程可以在事务中执行更新/插入/删除操作。在提交之前,他们可以检查表是否包含一个null
或任意数量的其他值。你可以合理地保持这一点。
在一天结束时,您的设计会产生难以实施的异常限制。也许你可以重新审视这个设计。