0

似乎在 SQL Server 中,唯一索引将 NULL 视为“只是另一个值”,而不是在 SQL 的其余部分中与 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列中的任意数量的唯一值)?

4

2 回答 2

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.
于 2013-05-01T06:54:55.033 回答
0

因此,您需要一个null或任意数量的唯一编号。我不认为可以使用约束可靠地强制执行。

您可能会使用触发器。触发器必须回答以下问题:您是否将一行更新为null?是否已经有一行了null?您是否正在更新已经存在的行null?该触发器将是复杂且难以维护的。

您可以使用存储过程来操作表。存储过程可以在事务中执行更新/插入/删除操作。在提交之前,他们可以检查表是否包含一个null或任意数量的其他值。你可以合理地保持这一点。

归根结底,您的设计施加了难以实施的异常约束。也许你可以重新审视设计。

于 2013-05-01T06:45:05.020 回答