【问题标题】:Uniqueness constraint on multiple columns causes issue with null values多列的唯一性约束导致空值问题
【发布时间】:2017-08-16 15:09:29
【问题描述】:

根据 oracle 文档,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

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

编辑

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

【问题讨论】:

  • 所以如果它忽略空值 1=1 并且它会违反约束对吗? (它已经忽略了空值)等于和不等于参考=<>. is not nullis null 是空安全操作,可以与空值进行比较。所以 null 被比较为 col2 的 null 因此它们相等所以 1 = 1 因为所有数据都匹配(重复)
  • 您真正想要发生什么?这两个插入都是允许的,但是两个具有相同col1 和相同非空col2 的插入不会?您将如何使用col1 = 1 区分这两行?

标签: oracle


【解决方案1】:

这就是the documentation says(强调添加):

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

它正在做它应该做的事情。在您的两个示例插入中,两个(潜在)行在一个键列中都包含 null,而在另一个键列中包含相同的值 (1),因此违反了约束。

没有其他东西真正有意义;无论如何,允许两个插入操作都会给您留下两个无法区分的行。


你问:

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

因为没有其他键列可以强制唯一性。

正如你所说,null 不等于或不等于任何东西。如果您的唯一键仅在 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);

同样适用;它们的空值被有效地忽略了,但是现在 - 与单列键一样 - 没有什么可以强制唯一性了。

【讨论】:

  • 我知道它正在做它应该做的事情。我试图了解这种行为背后的基本原理。更新了我的问题。
【解决方案2】:

如果你真的想要一个忽略空值并且只阻止插入完整重复键的约束,那么你可以使用基于函数的唯一索引,它只保存完全非空的键:

create unique index uniq_col1_col2 on table1
  ( case when col1 is not null and col2 is not null then col1 end
  , case when col1 is not null and col2 is not null then col2 end
  );

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-02-17
    • 1970-01-01
    • 2017-05-27
    • 2013-01-07
    • 1970-01-01
    • 2013-09-16
    • 2014-10-01
    • 2013-06-14
    相关资源
    最近更新 更多