当涉及的字段之一为 NULL 时,MySQL 错误地允许重复条目
Posted
技术标签:
【中文标题】当涉及的字段之一为 NULL 时,MySQL 错误地允许重复条目【英文标题】:MySQL falsely allowing duplicate entries when one of the fields involved is NULL 【发布时间】:2014-03-08 21:17:01 【问题描述】:使用 InnoDB/mysqli,我有一个简单的表:mytable
。该表有四个字段:id
(primary, auto_inc)、field1
、field2
、field3
。都是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 生成“重复”错误?
编辑:这是以前作为“错误”添加到 MySQL 的:http://bugs.mysql.com/bug.php?id=25544
【问题讨论】:
【参考方案1】:您无法比较 NULL(如果您将任何内容与 NULL 进行比较,即使 NULL=NULL,结果始终是 FALSE
)此行为记录在 MySQL ref.
一个 UNIQUE 索引创建一个约束,使得索引中的所有值 必须是不同的。如果您尝试添加带有 与现有行匹配的键值。对于所有引擎,唯一 index 允许包含 NULL 的列有多个 NULL 值。
所以我认为唯一的方法是定义列 NOT NULL 或在触发器中处理此问题。
【讨论】:
【参考方案2】:问题的根源是 - 与 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 值。
【讨论】:
【参考方案3】:转到:How to Use Unique Indexes in MySQL and Other Databases 并查看“MySQL NULLs”部分。
【讨论】:
如果这是正确的,那么答案是它无法完成 - 我根本无法在唯一索引中使用可以为 NULL 的字段并避免我遇到的问题。将来,您对问题的贡献(即简单地提供链接)最好是作为评论而不是答案。 MySQL 在这种情况下将 NULL 值视为无法与另一个值进行比较的空值,因此它不会抛出任何异常。我会提供评论而不是回答,但我是 14 分。一次的缩写;-D 抱歉,我忘记了您需要一定的声誉等级才能添加 cmets :)以上是关于当涉及的字段之一为 NULL 时,MySQL 错误地允许重复条目的主要内容,如果未能解决你的问题,请参考以下文章