如何在NULL列上创build唯一索引?
我正在使用SQL Server 2005.我想约束列中的值是唯一的,同时允许NULLS。
我目前的解决scheme涉及一个独特的索引,如下所示:
CREATE VIEW vw_unq WITH SCHEMABINDING AS SELECT Column1 FROM MyTable WHERE Column1 IS NOT NULL CREATE UNIQUE CLUSTERED INDEX unq_idx ON vw_unq (Column1)
任何更好的想法?
很确定你不能这样做,因为它违背了唯一的目的。
不过,这个人似乎有一个体面的工作: http : //sqlservercodebook.blogspot.com/2008/04/multiple-null-values-in-unique-index-in.html
使用SQL Server 2008,您可以创build一个筛选的索引: http : //msdn.microsoft.com/en-us/library/cc280372.aspx 。 (我看到西蒙补充说这是一个评论,但认为这是值得它自己的答案,因为评论很容易错过)
另一个选项是检查唯一性的触发器,但这可能会影响性能。
计算的专栏技巧被广为人知地称为“黑名单”。 我的笔记信用史蒂夫卡斯:
CREATE TABLE dupNulls ( pk int identity(1,1) primary key, X int NULL, nullbuster as (case when X is null then pk else 0 end), CONSTRAINT dupNulls_uqX UNIQUE (X,nullbuster) )
严格来说,一个唯一可空的列(或一组列)可以是NULL(或一个NULL的logging)只有一次,因为具有相同的值(包括NULL)不止一次明显违反了唯一约束。
但是,这并不意味着“唯一可空列”的概念是有效的; 为了在任何关系数据库中实际实现它,我们必须牢记这种数据库是为了正常工作而规范化的,规范化通常包括添加几个(非实体)额外表来build立实体之间的关系。
我们来看一个基本的例子,只考虑一个“独特的可空列”,很容易将其扩展到更多的列。
假设我们用这样的表格表示的信息:
create table the_entity_incorrect ( id integer, uniqnull integer null, /* we want this to be "unique and nullable" */ primary key (id) );
我们可以通过将uniqnull分开,并添加第二个表来build立uniqnull值和the_entity之间的关系(而不是在the_entity内部有uniqnull“):
create table the_entity ( id integer, primary key(id) ); create table the_relation ( the_entity_id integer not null, uniqnull integer not null, unique(the_entity_id), unique(uniqnull), /* primary key can be both or either of the_entity_id or uniqnull */ primary key (the_entity_id, uniqnull), foreign key (the_entity_id) references the_entity(id) );
要将uniqnull的值关联到the_entity中的行,我们还需要在参考中添加一行。
对于在the_entity中的行没有uniqnull值是相关联的(即我们将NULL放在the_entity_incorrect中),我们只是不要在参数中添加一行。
请注意,uniqnull的值对于所有的相关性都是唯一的,并且还要注意,对于the_entity中的每个值,在相关中最多只能有一个值,因为其上的主键和外键都强制执行此操作。
那么,如果将uniqnull的值设为5与3的the_entity_id相关联,则需要:
start transaction; insert into the_entity (id) values (3); insert into the_relation (the_entity_id, uniqnull) values (3, 5); commit;
而且,如果the_entity的id值为10,那么我们只做:
start transaction; insert into the_entity (id) values (10); commit;
为了使这个信息非规范化并获得像the_entity_incorrect这样的表格,我们需要:
select id, uniqnull from the_entity left outer join the_relation on the_entity.id = the_relation.the_entity_id ;
“left outer join”操作符确保来自the_entity的所有行都将出现在结果中,在相关列中不存在匹配列时,将uniqnull列中的值放入NULL。
请记住,在devise一个规范化的数据库(以及相应的反规范化视图和程序)的过程中,花费数天(或数周或数月)的努力将为您节省数年(或数十年)的痛苦和浪费的资源。