当其中一个字段为NULL时,MySQL错误地允许重复条目

时间:2014-02-11 07:41:06

标签: php mysql sql mysqli

使用InnoDB / MySQLi,我有一个简单的表:mytable。该表有四个字段:id(主要,auto_inc),field1field2field3。所有这些都是BIGINT,除了id之外,它们可以是NULL

我添加了一个像这样的唯一约束:

ALTER TABLE mytable ADD UNIQUE INDEX(field1,field2,field3);

但是,我完全能够添加以下行而不会生成任何错误。我希望这会产生“重复”错误,但它不会:

INSERT INTO mytable VALUES (NULL,3,NULL)
INSERT INTO mytable VALUES (NULL,3,NULL)

如果所有字段都具有非NULL值,它只会生成“重复”错误 - 例如,

INSERT INTO mytable VALUES (2,3,4)
INSERT INTO mytable VALUES (2,3,4)

即使一个(或多个)字段具有NULL值,如何告诉MySQL生成“重复”错误?

编辑:这是以前作为“bug”添加到MySQL:http://bugs.mysql.com/bug.php?id=25544

3 个答案:

答案 0 :(得分:5)

您无法比较NULL(如果您将任何内容与NULL进行比较,即使NULL = NULL,结果始终为FALSEMySQL ref.

中记录了此行为
  

UNIQUE索引创建一个约束,以便索引中的所有值   必须是截然不同的如果您尝试使用a添加新行,则会发生错误   与现有行匹配的键值。对于所有引擎,都是独一无二的   index允许包含NULL的列的多个NULL值。

所以我认为唯一的方法是定义列NOT NULL或在触发器中处理此问题。

答案 1 :(得分:3)

问题的根源是 - 比较NULL-s。你应该理解NULL的逻辑含义。而且它“没有价值”。不是“零值”“未知值”,但“无价值”。这是一个很大的不同。

这就是为什么使一部分唯一索引为NULL的原因当然是个坏主意。您无法比较NULL,因为您无法比较两个值,两个值都不存在。因此,只要比较不以正常方式适用于它们,DBMS就不能保持NULL-s是唯一的。是的,<=>运算符存在于MySQL(或其他DBMS中的IS NULL)中 - 但这是关于如何处理与NULL值进行比较的技术解决方案 - 但不是逻辑。

所以你在XY-problem的中间。不要将NULL-s与唯一键一起使用 - 它们不能定义什么是NULL以及什么是唯一键的意图。从technical viewpoint(参见有关索引创建的部分),NULL=NULL将始终导致 false - 因此,如果存在另一个NULL值,则允许插入NULL值。< / p>

答案 2 :(得分:1)

转到:How to Use Unique Indexes in MySQL and Other Databases 并查看“MySQL NULLs”部分。