报错因列中存在重复值,mysql 5.7+ 严格校验;需先查重(select col, count() group by col having count() > 1)、清理冗余数据或改用组合索引,再执行 add unique;null 值不互斥,显式命名约束更易维护。

ALTER TABLE 添加唯一约束时,为什么报错 Duplicate entry?
直接执行 ALTER TABLE table_name ADD UNIQUE (column_name) 会失败,如果该列已有重复值。MySQL 在添加约束前会校验全表数据,遇到重复就中断并报错 Duplicate entry 'xxx' for key 'column_name'。
解决办法是先清理或合并重复数据:
- 查出重复项:
SELECT column_name, COUNT(*) FROM table_name GROUP BY column_name HAVING COUNT(*) > 1 - 根据业务逻辑删掉冗余行,或用
UPDATE统一值(如保留最小id对应的记录) - 确认无重复后,再执行添加约束
给多个字段联合加唯一约束,语法和单字段有啥区别?
联合唯一约束不是写成 UNIQUE(col1, col2) 就完事——括号里必须是字段列表,且不能带空格或逗号外的符号。常见错误是误写成 UNIQUE(col1), UNIQUE(col2)(这是两个单列约束),或漏掉括号。
正确写法:
ALTER TABLE users ADD UNIQUE (email, tenant_id);
注意:
- 约束名可选但推荐显式指定:
ADD CONSTRAINT uk_user_email_tenant UNIQUE (email, tenant_id),便于后续DROP INDEX或排查错误信息 - 联合约束对
NULL的处理:MySQL 认为多个NULL不冲突,所以 (‘a’, NULL) 和 (‘a’, NULL) 是允许的
用 CREATE TABLE 一次性建表+加唯一约束,怎么避免命名冲突?
建表时直接定义约束,比建完再 ALTER 更安全,但约束名若不显式指定,MySQL 会自动生成(如 email 列的约束叫 email),容易在迁移或复制表时因重名报错 ERROR 1022: Can't write; duplicate key in table。
建议始终手动命名:
CREATE TABLE orders ( id INT PRIMARY KEY, order_no VARCHAR(32), user_id INT, UNIQUE KEY uk_order_no (order_no) );
关键点:
-
UNIQUE KEY和UNIQUE效果一样,但前者更明确,也兼容旧版本语法 - 约束名(如
uk_order_no)必须在当前库中唯一;不同表可以同名,但不推荐,不利于运维定位 - 如果字段本身是
PRIMARY KEY或已建INDEX,MySQL 可能复用索引,但别依赖这点——唯一约束一定会创建对应索引
删除唯一约束时,为什么 DROP INDEX 比 ALTER TABLE 更可靠?
用 ALTER TABLE table_name DROP INDEX index_name 是最稳妥的方式。而 ALTER TABLE table_name DROP CONSTRAINT constraint_name 在 MySQL 中不被支持(仅适用于 SQL Server/Oracle),强行写会报错 ERROR 1091: Can't DROP 'xxx'; check that column/key exists。
所以得先查约束对应的索引名:
SHOW INDEX FROM table_name WHERE Key_name LIKE 'uk%';
然后删索引:
- 如果建约束时没指定名字,MySQL 通常用字段名当索引名(如
email列的唯一索引名就是email) - 联合约束的索引名默认是第一个字段名(如
(email, tenant_id)的索引名可能是email),所以务必用SHOW INDEX确认 - 删完索引,约束自然失效;不需要额外操作
约束名和索引名在 MySQL 里是绑定的,但底层只认索引。别被 “constraint” 这个词误导,操作对象永远是索引。











