添加 NOT NULL 约束会失败,根本原因是列中存在 NULL 值;必须先用 UPDATE 填充空值、确认无 NULL 后,再用 MODIFY 或 CHANGE 添加约束,且需注意锁表风险与应用层 SQL 兼容性。

ALTER TABLE 添加 NOT NULL 约束会失败?先看字段有没有 NULL 值
直接执行 ALTER TABLE t ADD COLUMN name VARCHAR(50) NOT NULL 或修改现有列时加 NOT NULL,MySQL 会报错 ERROR 1265 (01000): Data truncated for column 'name' at row X 或更直白的 ERROR 1138: Invalid use of NULL value——根本原因是该列已有 NULL 值,而 NOT NULL 不允许存在。
必须先清理或填充数据,再加约束。常见做法是:
- 用
UPDATE把空值设为默认值(比如空字符串、0、'unknown'),注意类型要匹配:UPDATE t SET name = '' WHERE name IS NULL - 确认无
NULL:运行SELECT COUNT(*) FROM t WHERE name IS NULL,结果必须为 0 - 再执行
ALTER TABLE t MODIFY name VARCHAR(50) NOT NULL(MODIFY保留列位置;若需改列名用CHANGE)
MODIFY vs CHANGE:改非空约束时选哪个?
两者都能加 NOT NULL,但语义和风险不同。
-
MODIFY只改类型和约束,不改列名,语法简洁:ALTER TABLE t MODIFY age INT NOT NULL -
CHANGE必须重复写列名,适合同时重命名:ALTER TABLE t CHANGE old_name new_name VARCHAR(32) NOT NULL - 误用
CHANGE漏写新列名会导致语法错误:ERROR 1064;漏写NOT NULL则约束没加上,表面成功实则无效 - 二者都会锁表(尤其大表),线上操作前务必在从库或低峰期验证
添加 NOT NULL 后应用报错:检查 INSERT 和 UPDATE 语句
约束生效后,所有写入都必须显式提供值。容易被忽略的是:
- INSERT 语句省略该列(且无默认值)→ 报错
ERROR 1364: Field 'xxx' doesn't have a default value - 使用
INSERT INTO t() VALUES()这类空字段列表,或 ORM 自动生成 SQL 时未包含该列 - UPDATE 时设为
NULL(如SET status = NULL)→ 直接拒绝 - 解决方法:要么补全 INSERT 字段,要么给列加
DEFAULT(如DEFAULT ''),但注意DEFAULT和NOT NULL是正交的,不互斥
INT 类型加 NOT NULL 却存了 0?小心隐式转换陷阱
对已存在的 INT 列加 NOT NULL 后,如果原数据有空字符串 '' 或非法字符,MySQL 5.7+ 严格模式下会报错;但兼容模式可能静默转成 0,导致数据失真。
- 执行前查异常值:
SELECT * FROM t WHERE name = '' OR name REGEXP '[^0-9]'(假设是数字列) - INT 列本身不能存字符串,但弱类型上下文(如字符串拼接、函数参数)可能触发隐式转换,加约束不解决这类逻辑问题
- 真正安全的做法:先用
ALTER TABLE ... CHANGE显式指定类型+约束,并确认sql_mode包含STRICT_TRANS_TABLES
约束只是兜底,不是数据清洗的替代品。加之前到底有没有脏数据,比语法对不对更重要。


















