严格地说,一个独特的可空列(或一组列)可以只有一次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中。请记住,花费几天(或几周或几个月)来设计一个规范化的数据库(以及相应的反规范化视图和过程)的任何努力将为您节省数年(或数十年)的痛苦和浪费的资源。
使用sql 2008没有机会?你可以使用'where'创建一个过滤的索引 – 2010-03-13 03:21:02
你不是指_unique,允许NULLs_,你似乎意味着_unique,但包括多个NULLs_。否则,NULL与其他任何值一样被编入索引,唯一性约束按预期工作 - 只是不符合SQL标准,如下面评论中提到的@pst。 – Suncat2000 2012-02-09 14:28:26