严格来说,一个唯一可空列(或一组列)只能为 NULL(或一条记录的 NULLs),因为具有相同的值(包括 NULL)超过一次明显违反了唯一限制。
但是,这并不意味着“唯一可空列”的概念无效;要在任何关系数据库中实际实现它,我们只需记住这种类型的数据库旨在归一化以正常工作,并且归一化通常涉及添加几个(非实体)额外表来建立实体之间的关系。
让我们考虑一个仅涉及一个“唯一可空列”的基本示例,很容易将其扩展到更多这样的列。
假设我们使用如下所示的表表示的信息:
create table the_entity_incorrect
(
id integer,
uniqnull integer null,
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 (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的值对于所有the_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 没有唯一的对应项,我们只需要执行以下操作:
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
;
"左外连接"运算符确保结果中出现来自the_entity的所有行,在没有匹配列的情况下,将NULL放入uniqnull列。
请记住,花费几天(或几周或几个月)设计规范化的数据库(以及相应的反规范化视图和过程)将为您节省数年(甚至数十年)的痛苦和浪费资源。