ALTER TABLE 添加 UNIQUE 约束的正确语法是 ALTER TABLE table_name ADD UNIQUE (column_name),若列存在重复非 NULL 值则失败,需先查重清理;支持多列组合唯一,推荐显式命名约束以便后续管理。

ALTER TABLE 添加 UNIQUE 约束的正确语法
直接对已有字段加唯一约束,必须用 ALTER TABLE ... ADD UNIQUE,不能用 MODIFY COLUMN 或 CHANGE COLUMN 试图“重定义字段”来捎带加约束——那样只会报错或静默忽略 UNIQUE 关键字。
基本写法是:
ALTER TABLE `table_name` ADD UNIQUE (`column_name`);
如果该字段允许 NULL,MySQL 会把所有 NULL 值视为互不冲突(符合 SQL 标准),所以能成功添加;但只要存在重复的非 NULL 值,命令会立即失败并提示 Duplicate entry 错误。
添加前必须清理重复数据
这是最常卡住的地方:不是语法不会写,而是表里早有重复值。MySQL 不会帮你去重,它只拒绝执行。
先查有没有重复:
SELECT `column_name`, COUNT(*) FROM `table_name` GROUP BY `column_name` HAVING COUNT(*) > 1;
如果有结果,必须人工决定怎么处理——删掉冗余行、合并业务逻辑、或用 UPDATE 统一成某个值。常见做法包括:
- 保留最小
id的那条,删其余:DELETE t1 FROM table_name t1 INNER JOIN table_name t2 WHERE t1.column_name = t2.column_name AND t1.id > t2.id; - 用
GROUP BY+MIN(id)构造临时白名单再DELETE - 如果字段是字符串且允许微调,可加时间戳后缀临时去重,后续再清洗
给联合字段加唯一约束(多列组合唯一)
单字段不够用时,往往需要保证几列组合起来不重复,比如 (user_id, category) 不能重复。
语法一样,只是括号里写多个字段名,用逗号分隔:
ALTER TABLE `table_name` ADD UNIQUE (`user_id`, `category`);
注意点:
- 列顺序不影响约束逻辑,但影响索引 B+ 树的排序方式,查询时用到
WHERE user_id = ? AND category = ?最高效;只查category则无法走这个索引 - 其中任意一列允许
NULL,整行仍可能被判定为“不重复”,因为(1, NULL)和(1, NULL)在 MySQL 中不视为重复(NULL != NULL) - 约束名可选,但建议显式指定,方便后续
DROP:ADD UNIQUE KEY uk_user_cat (user_id, category)
删除唯一约束时别找错名字
加的时候没起名,MySQL 会自动命名(通常是字段名或前几个字段拼接),但不同版本规则不同,不能靠猜。
先查真实约束名:
SHOW INDEX FROM `table_name` WHERE Key_name != 'PRIMARY';
找到 Key_name 列对应的值,再执行:
ALTER TABLE `table_name` DROP INDEX `uk_user_cat`;
容易踩的坑:
- 误以为
DROP UNIQUE是合法语法 —— 实际上 MySQL 没这写法,必须用DROP INDEX - 在从库上执行后忘记检查主从延迟,导致从库同步中断(尤其大表加约束会锁表)
- 应用层已有逻辑假设该字段“自然唯一”,加约束后突然报错,其实是暴露了原本就存在的脏数据或并发写入漏洞
加唯一约束不是一劳永逸,它把校验从应用层推给了存储层,但前提是数据得先干净,而且你要清楚 NULL 怎么算、联合索引怎么用、出错时日志里真正拦住你的是哪一行。


















