多列的唯一约束 - 允许单个null

时间:2014-11-06 15:31:41

标签: sql oracle

我发现了这个:Unique constraint on multiple columns

SQL> CREATE TABLE t (id1 NUMBER, id2 NUMBER);

Table created
SQL> ALTER TABLE t ADD CONSTRAINT u_t UNIQUE (id1, id2);

Table altered
SQL> INSERT INTO t VALUES (1, NULL);

1 row inserted
SQL> INSERT INTO t VALUES (1, NULL);

INSERT INTO t VALUES (1, NULL)

ORA-00001: unique constraint (VNZ.U_T) violated

我想创建一个允许输入多个(X,null)值的约束,以便约束仅在约束所涉及的BOTH值不为空时启动。这可能吗?

2 个答案:

答案 0 :(得分:3)

在这种情况下你需要一个CHECK约束:

ALTER TABLE t ADD CONSTRAINT chk_t CHECK (id1 is null or id2 is null);

如果您需要一个独特的约束行为,您可以尝试这样做:

drop table t1;
create table t1 (n number, m number);
create unique index t_inx on t1(case when n is null then null when m is null then null else n || '_' || m end);
insert into t1 values (1, null);
insert into t1 values (1, null);
insert into t1 values (null, 1);
insert into t1 values (null, 1);
insert into t1 values (1, 1);
insert into t1 values (1, 1);
insert into t1 values (1, 2);

基于唯一函数的索引

答案 1 :(得分:3)

请注意,您可以插入多个(NULL,NULL),但不能插入多个(1,NULL)。这就是索引在Oracle中的工作方式;当所有列都为null时,索引中没有条目。

因此,不是在(id1,id2)上构建正常索引,而是必须构建一个函数索引,当至少一个为null时,使两个值都为null。我们需要确定性的功能。第一个要检查null的DECODE。然后使用GREATEST,当至少有一个值为null时,使用它会导致null:

create unique index idx_t_unique on t 
( 
  decode(greatest(id1,id2),null,null,id1), 
  decode(greatest(id1,id2),null,null,id2) 
);
编辑(接受后:-)我只是看,你不需要确定性函数,但也可以使用案例结构。也许情况总是如此,也许不是,我不知道。但是,如果您发现索引更具可读性,也可以按如下方式编写索引:

create unique index idx_t_unique on t 
(
  case when id1 is null or id2 is null then null else id1 end,
  case when id1 is null or id2 is null then null else id2 end
);