最近遇到一个问题,我为一张表中创建了一个唯一键,并且键中字段为NULL,最终导致了唯一约束失效。这里做下分析:

首先新建一张表,包含 work_no,name,age 三个字段:

DROP TABLE IF EXISTS t_emp;
CREATE TABLE t_emp(id int(8) not null auto_increment,work_no varchar(8) comment  '工号',name varchar(255) comment '姓名',age int(3) comment '年龄',primary key(id),unique key(work_no,name,age)
)engine=InnoDB,charset=UTF8mb4,comment="员工表";

从创建语句中我们可以看到,我们为工号,姓名,年龄上添加了唯一约束,现在我们尝试插入数据:

insert into t_emp(work_no,name,age) values ('9527','张三',23);
insert into t_emp(work_no,name,age) values ('9527','张三',23);

我们在尝试插入第二条数据时会报错:

(1062, “Duplicate entry ‘9527-张三-23’ for key ‘work_no’”)

可见唯一键是生效了的,现在我们尝试将 age 为 null 再次尝试下:

insert into t_emp(work_no,name,age) values ('9527','张三',NULL);
insert into t_emp(work_no,name,age) values ('9527','张三',NULL);

可以看到当 age 为空时附加在该字段上的唯一约束失效了。

首先我们可以确认 null 值的出现破坏了唯一性,原本应该被唯一约束限制到的记录被插入到了表中。

如何确保 NULL 不破坏唯一性?

  • 不允许列出现 NULL 值,即NOT NULL
  • 给列增加 DEFUALT 值,注意 DEFAULT 不能是 NULL

所以需要调整建表语句:

DROP TABLE IF EXISTS t_emp;
CREATE TABLE t_emp(id int(8) not null auto_increment,work_no varchar(8) NOT NULL DEFAULT '' comment  '工号',name varchar(255) NOT NULL DEFAULT '' comment '姓名',age int(3) NOT NULL DEFAULT 0 comment '年龄',primary key(id),unique key(work_no,name,age)
)engine=InnoDB,charset=UTF8mb4,comment="员工表";

简单来说就是不要在唯一约束上使用 NULL,但是空字符串是可以的。

如果我们再继续寻找其根本原因的话,就要探究 NULL 在 MySQL 中的实现原理了。

深度探讨

关于NULL 值是否应该被唯一约束限制到的问题,早年有人向 MySQL 开发提出过问题。具体可以参考文档,可以看到开发者给出的解释是:

感兴趣的童鞋可以点进去看下,关于这个问题是否是一个BUG 的问题探讨的还是很激烈的。最终结果还是显而易见的,MySQL 保留了空值不受唯一约束的限制的这个特性。开发者通过调整空值为空字符串来处理该类异常问题。

NULL 与 NULL 不相等

还记得在 MySQL 中如何以字段值为 NULL 作为条件查询吗?

SELECT * FROM t_emp WHERE age IS NULL;

NULL 在 MySQL 中作为一个特殊的存在,我们无法使用平常使用的等值查询进行查询:

MySQL root@localhost:test> select null = null;
|| null = null ||
| <null> |
1 row in set
Time: 0.001s
MySQL root@localhost:test> SELECT NULL IS NULL;
|| NULL IS NULL ||
| 1 |
1 row in set
Time: 0.001s

比如我们有一个单列的唯一索引,既然实际会有空值的情况,如果唯一约束对空值也有起作用,就会导致仅有一行数据可以为空,这可能会和实际的业务需求相冲突的。所以通常MySQL的存储引擎的唯一索引对NULL值是不适用的。 这也就倒是联合唯一索引的情况下,只要某一列为空,就不会报唯一索引冲突。

或者说,我们一般认为在 MySQL 中 NULL 是一个没有被赋值的值,既然没有被赋值,那么它就有可能被赋值为任意值。这样就可以理解为两个任意值不相等,也就是两个 NULL 值是不相等的,因此也就可以在 唯一索引中单独存在了。

面试题:主键索引与唯一索引的区别

  • 唯一索引的索引列允许空值,而主键索引的列不允许空值

    • 唯一索引列存在空值时,唯一约束对空值时不生效的
  • 主键索引可以被引用为外键,而唯一索引不能
  • 一个表中最多只能创建一个主键索引,单可以创建多个唯一索引

主键索引 = 唯一索引 + 唯一约束 + 非空约束
唯一索引 = 唯一索引 + 唯一约束

参考资料

MySQL: 唯一索引与NULL
Mysql 唯一索引的字段值
Bug #8173 unique index allows duplicates with null values

MySQL 中 NULL 导致唯一键失效相关推荐

  1. MySQL 中NULL和空值的区别?

    做一个积极的人 编码.改bug.提升自己 我有一个乐园,面向编程,春暖花开! 01 小木的故事 作为后台开发,在日常工作中如果要接触Mysql数据库,那么不可避免会遇到Mysql中的NULL和空值.那 ...

  2. MySQL并发insert因唯一键导致的DeadLock

    业务场景为:一个业务中向A表插入数据多条,同时向B表插入多条纪录,两张表都有组合唯一键,使用jmeter进行并发测试时出现死锁现象! <==== 一个业务同时向两张表中插入数据,同样的组合唯一索 ...

  3. mysql主键和唯一键的区别

    什么是主键? 主键是表中唯一标识该表中每个元组(行)的列.主键对表实施完整性约束.表中只允许使用一个主键.主键不接受任何重复值和空值.表中的主键值很少更改,因此在选择主键是需要小心,要选择很少发生更改 ...

  4. mysql''和null,mysql中NULL和null的区别

    接触php的web开发一段时间了,在进行数据库操作的时候经常会遇到一个问题,使得同一字段在页面显示时有3种类型NULL,null以及数字,当时的解决办法是将这一字段定义为varchar类型,在插入数据 ...

  5. MySQL从入门到精通50讲(十)-MySQL中null值如何处理

    MySQL NULL 值处理 我们已经知道MySQL使用 SQL SELECT 命令及 WHERE 子句来读取数据表中的数据,但是当提供的查询条件字段为 NULL 时,该命令可能就无法正常工作. 为了 ...

  6. mysql中的钱null,mysql 中null总结

    ====================== 相信很多用了mysql很久的人,对这两个字段属性的概念还不是很清楚,一般会有以下疑问: 1.我字段类型是not null,为什么我可以插入空值 2.为毛n ...

  7. MySQL 中NULL和空值的区别

    平时我们在使用MySQL的时候,对于MySQL中的NULL值和空值区别不能很好的理解.注意到NULL值是未知的,且占用空间,不走索引,DBA建议建表的时候最好设置字段是NOT NULL 来避免这种低效 ...

  8. mysql中null值求和_sql求和涉及到null值

    SQL ISNULL().NVL().IFNULL() 和 COALESCE() 函数 请看下面的 "Products" 表: P_Id ProductName UnitPrice ...

  9. 在MySQL中 NULL的含义是_mysql null的含义是什么

    mysql null的含义:1.如在普通的字段中,空值就是表示空值:2.如果将一个空值的数据插入到TimesTamp类型的字段中,空值就不一定为空. mysql null的含义: 空值是不占用空间的, ...

最新文章

  1. 职场社交:做职场版微信不如做职场版微博
  2. 数据浪潮上的IP雄鹰
  3. SimBERTv2来了!融合检索和生成的RoFormer-Sim模型
  4. Leetcode怎么调试java代码,IDEA2020.1使用LeetCode插件运行并调试本地样例的方法详解...
  5. Wireshark数据包分析(一)——使用入门
  6. 一文读懂区块链以及一个区块链的实现
  7. 【STM32】【STM32CubeMX】STM32CubeMX的使用之八:低功耗模式及MCU唤醒
  8. Linux的触屏手势软件安装,如何添加Mac的多点触控手势到Ubuntu | MOS86
  9. 2.7配置自定义的Formatters
  10. 7月25日训练赛签到题HDU1257
  11. OpenGL 驱动 与 扩展的关系
  12. pyecharts源码解读(15)图表类包charts之组合图表: 选项卡Tab
  13. 2022 职业院校移动开发总结(uni-app)
  14. happen-before原则
  15. android PMU
  16. 请问现在好多抖音巨量广告落地页pages.tmall.com的页面如何生成
  17. 标签打印软件如何设置打印区域
  18. queue.queue是什么
  19. storage/emulated/0.到底在哪儿
  20. JasperReports初体验

热门文章

  1. 设置Symantc内部LiveUpdate服务器注意事项
  2. oppo锁频段_给大家科普下现在的OPPO Reno3支持哪几个5G频段
  3. 如何计算黄金分割比例
  4. qt linux获取安装目录路径
  5. Selenium IDE使用指南四(代码导出)
  6. 想要创业,注册公司需要什么流程和资料?
  7. 深度学习在医学图像处理中的应用
  8. SWUST OJ#1051(数据结构之输出利用先序遍历创建的二叉树中的指定结点的Child结点)
  9. 2021全新改版影视app系统源码(全开源)
  10. 有一种胸襟,叫“我搭台 你唱戏” 有一种气魄,叫“我做平台 大家赚钱”