ALTER TABLE 添加主键失败因字段存在NULL或重复值;外键添加需满足InnoDB引擎、类型严格一致及被引用列有索引;CHECK约束仅MySQL 8.0.16+原生支持;UNIQUE与NOT NULL须分步添加。

ALTER TABLE 添加主键约束时为什么报错 Duplicate entry
主键约束要求字段值非空且唯一,如果表中已有重复值或 NULL 值,ALTER TABLE ... ADD PRIMARY KEY 会直接失败,错误信息类似 Duplicate entry '' for key 'PRIMARY' 或 Cannot add or update a child row: a foreign key constraint fails。
- 先检查目标字段是否有 NULL 或重复值:
SELECT col, COUNT(*) FROM table_name GROUP BY col HAVING COUNT(*) > 1 OR col IS NULL; - 清理数据后再执行,例如用
UPDATE填充 NULL、用DELETE去重,或添加NOT NULL后再设主键 - 若字段是自增 ID,建议先
ALTER TABLE table_name MODIFY id INT AUTO_INCREMENT;再加主键,避免隐式类型不匹配
外键约束添加失败的三个常见原因
MySQL 中外键(FOREIGN KEY)依赖存储引擎(仅 InnoDB 支持)、字段类型严格一致、以及被引用列必须有索引。任意一项不满足都会报错,典型如 ERROR 1215 (HY000): Cannot add foreign key constraint。
- 确认两张表都是
ENGINE=InnoDB:用SHOW CREATE TABLE parent_table;查看,不是则先ALTER TABLE table_name ENGINE=InnoDB; - 检查字段类型是否完全一致:比如
INT和INT UNSIGNED不兼容,VARCHAR(20)和VARCHAR(25)也不行;字符集和排序规则(collation)也需相同 - 确保被引用列(通常是父表的主键或唯一索引列)已建索引:若没有,先执行
ALTER TABLE parent_table ADD INDEX (ref_col);
用 ALTER TABLE 添加 CHECK 约束要注意版本
MySQL 8.0.16+ 才支持原生 CHECK 约束,低版本(如 5.7)虽然能解析语法但会忽略,不报错也不生效。如果你在 5.7 执行 ALTER TABLE t ADD CHECK (age >= 0);,语句成功,但约束实际不存在。
- 验证是否生效:查
information_schema.CHECK_CONSTRAINTS表(8.0+),或用SHOW CREATE TABLE t;看输出里是否包含CHECK子句 - 低版本替代方案:靠应用层校验,或用触发器(
BEFORE INSERT/UPDATE)模拟,但性能开销大、逻辑分散 - 注意:CHECK 表达式不能含子查询、存储函数、参数化变量,也不能引用其它列的别名
UNIQUE 和 NOT NULL 约束可以合并添加但不能混用语法
添加唯一约束和非空约束是两个独立操作,MySQL 不支持像 ADD UNIQUE NOT NULL 这样的复合语法。误写会导致语法错误 ERROR 1064。
- 正确顺序:先
ALTER TABLE t MODIFY col VARCHAR(50) NOT NULL;(改列属性),再ALTER TABLE t ADD UNIQUE (col);(加索引级约束) - 如果该列已有数据且含 NULL,
MODIFY ... NOT NULL会失败,必须先处理 NULL 值 - UNIQUE 约束本身允许一个 NULL(标准行为),但若想彻底禁用 NULL,必须显式加
NOT NULL,否则仍可能存入空值干扰业务逻辑
ON DELETE CASCADE)、CHECK 的表达式求值时机(INSERT 时还是 UPDATE 时)、甚至字符集变更都可能让已有约束失效或行为突变——上线前务必在同版本环境完整验证。









