多列的唯一性约束会导致null值出现问题

San*_*osh 3 oracle

根据oracle docs,null不能等于或等于任何值或不等于null

在任何列的唯一性约束的情况下,这是显而易见的.但是,如果多列上的唯一性约束,则行为会有所不同.例如:

CREATE TABLE table1 (
    col1 NUMBER(2),
    col2 NUMBER(2),
    CONSTRAINT uniq_col1_col2 UNIQUE (col1, col2)
);
INSERT INTO table1 VALUES (1, NULL);
INSERT INTO table1 VALUES (1, NULL);
# ORA-00001: unique constraint (XYZ.UNIQ_COL1_COL2) violated
Run Code Online (Sandbox Code Playgroud)

为什么会这样?如何指定忽略空值的约束?

编辑

更具体地说,如果行(null), (null)是唯一的,为什么(1,null), (1,null)不是唯一的?这背后的理由是什么?

Ale*_*ole 5

这就是文档所说的内容(重点补充):

为了满足唯一约束,表中没有两行可以具有唯一键的相同值.但是,由单个列组成的唯一键可以包含空值.要满足复合唯一键,表或视图中的任何两行都不能在键列中具有相同的值组合.所有键列中包含空值的任何行都会自动满足约束.但是,包含一个或多个键列的空值的两行以及其他键列的相同值组合违反了约束.

它正在做它应该做的事情.使用两个示例插入时,两个(可能的)行在一个键列中包含null,在另一个键列中包含相同的值(1),因此违反了约束.

没有别的东西真的有意义; 无论如何,允许两个插入进行将为您留下两个难以区分的行.


您询问:

更具体地说,如果行(null), (null)是唯一的,为什么(1,null), (1,null)不是唯一的?这背后的理由是什么?

因为没有其他关键列可以强制执行唯一性.

如你所说,null不等于或不等于任何东西.如果你的唯一键只有on col1并且你有两行并且它被设置为null,这是允许的,那么查询where col1 is null会找到两者 - 这是好的,因为is null它不是关于相等的.您可以说两个行都匹配条件,但不是它们等于null.使用双列密钥,相当于where col1 = 1 and col2 is null.现在平等确实起作用了.

在这两种情况下,空值都被忽略,剩下的任何东西仍然必须是唯一的.使用单列密钥时,没有其他任何东西可以强制执行唯一性.使用双列键如果col2为null,则col1仍然需要进行比较,并且它本身必须是唯一的,有效的.

你也被允许这样做:

INSERT INTO table1 VALUES (null, null);
INSERT INTO table1 VALUES (null, null);
Run Code Online (Sandbox Code Playgroud)

同样的事情适用; 它们的空值被有效地忽略了,但是现在 - 就像单列密钥一样 - 没有什么可以强制执行唯一性.