2008-10-10 47 views
88

我正在使用SQL Server 2005.我想限制列中的值是唯一的,同时允许NULLS。如何在NULL列上创建唯一索引?

我目前的解决方案包括在像这样一个视图的唯一指标:

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) 

更好的想法?

+14

使用sql 2008没有机会?你可以使用'where'创建一个过滤的索引 – 2010-03-13 03:21:02

+3

你不是指_unique,允许NULLs_,你似乎意味着_unique,但包括多个NULLs_。否则,NULL与其他任何值一样被编入索引,唯一性约束按预期工作 - 只是不符合SQL标准,如下面评论中提到的@pst。 – Suncat2000 2012-02-09 14:28:26

回答

26

很确定你不能那样做,因为它违反了唯一标识的目的。

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

+2

看起来你提供的链接的内容实际上(部分)被复制,没有归属于此:http://decipherinfosys.wordpress.com/2007/11/30/multiple-null-values-in-a-unique-index -in-sql-serverdb2-luw/ – 2010-02-25 09:58:39

+71

我不同意它“违反唯一标识的目的”--NULL是SQL中的一个特殊值(与许多NaN类似)并需要相应处理。实际上,在SQL Server中未能遵守各种SQL规范:以下是“正确实现”请求的链接:http://connect.microsoft.com/SQLServer/feedback/details/299229 /更改唯一约束到允许海报无效值。 – 2010-08-08 05:08:42

+2

供2008年参考,你可以做CREATE UNIQUE INDEX foo ON dbo.bar(key)WHERE key IS NOT NULL; – niico 2017-05-03 16:06:15

68

计算列伎俩被广泛称为“nullbuster”;我的笔记信用史蒂夫卡斯:

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

使用SQL Server 2008中,您可以创建一个过滤索引:http://msdn.microsoft.com/en-us/library/cc280372.aspx。 (我看人妖添加这是一个评论,但认为它值得它自己的答案的评论很容易漏诊)

另一种选择是一个触发器来检查的独特性,但是这可能会影响性能。

0

严格地说,一个独特的可空列(或一组列)可以只有一次NULL(或一个NULL记录),因为具有相同的值(并且包括NULL)不止一次显然违反了唯一约束。

但是,这并不意味着“唯一可空列”的概念是有效的;为了在任何关系数据库中实际实现它,我们必须牢记这种数据库是为了正常工作而规范化的,规范化通常涉及添加几个(非实体)额外表来建立实体之间的关系。

让我们以一个仅考虑一个“唯一可空列”的基本示例为例,很容易将其扩展到更多这样的列。

假设我们用一个表像这样表示的信息:

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做“里面的” 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值关联(即对于那些我们将NULL放入the_entity_incorrect中的行),我们只是不在the_relation中添加一行。

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

然后,如果5 uniqnull值要与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; 

而且,如果值的10 the_entity的ID没有uniqnull对手,我们只做:

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”运算符可确保from_entity中的所有行都将显示在结果中,并在相关列中不存在匹配列时将uniqnull列中的值放入NULL中。请记住,花费几天(或几周或几个月)来设计一个规范化的数据库(以及相应的反规范化视图和过程)的任何努力将为您节省数年(或数十年)的痛苦和浪费的资源。

相关问题