如何在NULL列上创建唯一索引?

时间:2008-10-10 14:03:34

标签: sql sql-server indexing constraints unique

我正在使用SQL Server 2005.我想将列中的值限制为唯一,同时允许NULLS。

我当前的解决方案涉及视图上的唯一索引,如下所示:

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)

有更好的想法吗?

5 个答案:

答案 0 :(得分:101)

使用SQL Server 2008,您可以创建筛选索引:http://msdn.microsoft.com/en-us/library/cc280372.aspx。 (我看到西蒙补充说这是一个评论,但认为它应该得到自己的答案,因为很容易错过评论。)

另一个选项是检查唯一性的触发器,但这可能会影响性能。

答案 1 :(得分:71)

计算的列技巧被广泛称为“nullbuster”;我的笔记记录了Steve Kass:

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)
)

答案 2 :(得分:25)

很明显你不能这样做,因为它违反了独特的目的。

然而,这个人似乎有一个体面的工作: http://sqlservercodebook.blogspot.com/2008/04/multiple-null-values-in-unique-index-in.html

答案 3 :(得分:0)

可以使用过滤谓词来指定要包含在索引中的行。

来自documentation

<块引用>

WHERE 通过指定哪个过滤索引来创建过滤索引 要包含在索引中的行。过滤后的索引必须是 表上的非聚集索引。创建过滤的统计信息 过滤索引中的数据行。

示例:

CREATE TABLE Table1 (
  NullableCol int NULL
)

CREATE UNIQUE INDEX IX_Table1 ON Table1 (NullableCol) WHERE NullableCol IS NOT NULL;

答案 4 :(得分:-3)

严格地说,唯一可为空的列(或列集)只能为NULL(或NULL的记录),因为具有相同的值(并且这包括NULL)不止一次明显违反了唯一约束。 / p>

然而,这并不意味着&#34;独特的可空列&#34;已验证;要在任何关系数据库中实际实现它,我们必须记住,这种数据库应该被规范化以正常工作,并且规范化通常涉及添加几个(非实体)额外表来建立实体之间的关系

让我们的工作成为一个基本的例子,只考虑一个&#34;独特的可空列#34;它很容易将其扩展到更多这样的列。

假设我们用这样的表代表的信息:

create table the_entity_incorrect
(
  id integer,
  uniqnull integer null, /* we want this to be "unique and nullable" */
  primary key (id)
);

我们可以通过将uniqnull分开并添加第二个表来建立uniqnull值和the_entity之间的关系(而不是使用uniqnull&#34; inside&#34; the_entity)来实现:

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_relation中添加一行。

对于the_entity中的行没有关联uniqnull值(即对于我们在the_entity_incorrect中放置NULL的值),我们只是不在the_relation中添加一行。

请注意,uniqnull的值对于所有的in_relation都是唯一的,并且还注意到the_entity中的每个值在the_relation中最多只能有一个值,因为它上面的主键和外键强制执行此操作。

然后,如果uniqnull的值为5与the_entity id为3相关联,我们需要:

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没有uniqnull对应物,我们只会这样做:

start transaction;
insert into the_entity (id) values (10); 
commit;

要对此信息进行非规范化并获取像__entity_incorrect一样的表格,我们需要:

select
  id, uniqnull
from
  the_entity left outer join the_relation
on
  the_entity.id = the_relation.the_entity_id
;

&#34;左外连接&#34;运算符确保来自the_entity的所有行都将出现在结果中,当在replation中不存在匹配的列时,将NULL放在uniqnull列中。

请记住,在设计一个规范化的数据库(以及相应的非规范化视图和程序)中花费数天(或数周或数月)的任何努力都将为您节省数年(或数十年)的痛苦和资源浪费。