必须先清除列中所有NULL值才能成功添加NOT NULL约束,否则MySQL会报ERROR 1138;推荐用CHANGE COLUMN而非MODIFY COLUMN,并同步设置DEFAULT值以避免后续INSERT失败。

ALTER TABLE MODIFY COLUMN 加 NOT NULL 报错:ERROR 1138
直接写 ALTER TABLE t MODIFY col INT NOT NULL 很可能失败,尤其当该列已有 NULL 值时。MySQL 会拒绝这种“强制非空”操作,并抛出 ERROR 1138: Invalid use of NULL value —— 它不是语法错,而是数据校验拦截。
- 必须先确保该列所有现有行都不为 NULL,否则 MODIFY 不会执行
- 如果表大、NULL 值多,
UPDATE补默认值可能锁表或耗时,得提前评估影响 -
MODIFY会重定义整列定义(包括类型、长度、字符集等),哪怕只改约束,也容易误带副作用
更安全的做法:用 CHANGE COLUMN 或 ADD COLUMN + UPDATE + DROP
想只加 NOT NULL 约束,又不想碰类型定义,优先用 CHANGE COLUMN,它允许保持类型不变,只改约束和属性:
ALTER TABLE t CHANGE COLUMN col col INT NOT NULL;
注意这里字段名写了两遍(旧名、新名),中间是空格分隔,不是逗号 —— 写成逗号就语法错误。
- 如果列有默认值但没设 NOT NULL,
CHANGE仍需显式写出NOT NULL,不会自动继承 - 若列是主键或被外键引用,加 NOT NULL 通常没问题;但若依赖该列为 NULL 的业务逻辑存在,上线前务必检查应用层
- 某些 MySQL 版本(如 5.7 严格模式下)对空字符串转数值敏感,补默认值时别用
'0'强转INT字段,应直接写数字
NOT NULL 和 DEFAULT 要一起考虑
加了 NOT NULL 后,后续 INSERT 若不提供该列值,会报 ERROR 1364: Field doesn't have a default value。所以通常要同步配默认值:
ALTER TABLE t CHANGE COLUMN col col VARCHAR(32) NOT NULL DEFAULT 'unknown';
-
DEFAULT值必须符合字段类型,比如DATETIME列不能设DEFAULT '0',得用DEFAULT CURRENT_TIMESTAMP或具体时间字符串 - 如果字段已有大量数据,
DEFAULT只影响新插入行,不会自动填充旧数据 —— 这点常被忽略 - JSON、TEXT 类型在老版本 MySQL 中不支持 DEFAULT,加 NOT NULL 前得确认版本兼容性(5.7.8+ 才支持 JSON DEFAULT)
用 SHOW CREATE TABLE 验证结果是否生效
别只信 ALTER 语句没报错,执行完立刻查建表语句:
SHOW CREATE TABLE t;
看输出里对应列是否真的带了 NOT NULL,且没有意外多出 DEFAULT NULL 或其他冗余定义。
- 有些 ORM 或迁移工具生成的 SQL 会悄悄加上
DEFAULT NULL,跟 NOT NULL 冲突,MySQL 会静默忽略后者,导致你以为加成功了其实没加 - 如果字段是自增主键(
INT PRIMARY KEY AUTO_INCREMENT),它天然 NOT NULL,无需额外加 —— 但手动加也不会报错,只是多余 - 线上表结构变更,建议在低峰期做,并确认备份已就绪;加 NOT NULL 是 DDL,多数 MySQL 版本会锁表,尤其大表要格外小心
SELECT COUNT(*) FROM t WHERE col IS NULL,也别赌“应该没 NULL”。


















