不可行;MySQL不允许在单条ALTER TABLE语句中同时添加NOT NULL约束和DEFAULT值,因DEFAULT不填充历史NULL,必须先UPDATE补空值,再用MODIFY COLUMN分步添加约束与默认值。

ALTER TABLE 时直接加 NOT NULL 和 DEFAULT 是否可行
不行。MySQL 不允许在一条 ALTER TABLE ... MODIFY 或 ALTER TABLE ... CHANGE 语句中,同时添加 NOT NULL 约束和 DEFAULT 值——尤其当字段已有 NULL 数据时,会报错 ERROR 1138: Invalid use of NULL value 或 ERROR 1101: BLOB/TEXT column 'xxx' can't have a default value(对某些类型)。根本原因是:设为 NOT NULL 要求所有现有行都满足非空,而默认值只影响后续插入,不自动填充历史 NULL。
分两步安全添加:先填空再约束
必须拆成两个原子操作,且顺序不能颠倒:
- 第一步:用
UPDATE把当前表中该字段的NULL值全部替换为期望的默认值(例如''、0、CURRENT_TIMESTAMP) - 第二步:执行
ALTER TABLE ... MODIFY COLUMN,加上NOT NULL并指定DEFAULT
示例(给 users 表的 phone 字段补约束):
UPDATE users SET phone = '' WHERE phone IS NULL; ALTER TABLE users MODIFY COLUMN phone VARCHAR(20) NOT NULL DEFAULT '';
注意:MODIFY COLUMN 会重写整列数据,大表务必在低峰期操作;若字段是主键或有索引,不影响索引结构,但会触发 DML 锁。
使用 CHANGE COLUMN 的额外风险
如果误用 CHANGE COLUMN(比如只改名不改类型),可能意外丢失 DEFAULT 或 NOT NULL 属性。MySQL 的 CHANGE 和 MODIFY 在行为上细微不同:
-
MODIFY COLUMN只改类型、约束、默认值,不改列名 -
CHANGE COLUMN old_name new_name必须重写列定义,哪怕新旧名相同——此时若漏写NOT NULL或DEFAULT,原有约束就丢了
所以,只为加约束时,无条件选 MODIFY COLUMN;用 CHANGE 前务必确认完整列定义,例如:
ALTER TABLE users CHANGE COLUMN phone phone VARCHAR(20) NOT NULL DEFAULT '';
时间类型字段的 DEFAULT 特殊处理
TIMESTAMP 和 DATETIME 对 DEFAULT 语法敏感:
-
TIMESTAMP允许DEFAULT CURRENT_TIMESTAMP,但不能写DEFAULT NOW() -
DATETIME5.6.5+ 才支持DEFAULT CURRENT_TIMESTAMP,老版本只能用DEFAULT '2020-01-01 00:00:00' - 如果字段已存在且含 NULL,先
UPDATE填值时别用函数(如CURRENT_TIMESTAMP),否则每行时间戳全一样——应改用固定值或子查询生成差异时间
例如修复 created_at:
UPDATE users SET created_at = '2020-01-01 00:00:00' WHERE created_at IS NULL; ALTER TABLE users MODIFY COLUMN created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP;
真正麻烦的是大表 + 高并发场景:UPDATE 可能锁表数分钟,MODIFY COLUMN 又是一次全表重建。线上操作前,先在从库验证语句,再用 pt-online-schema-change 这类工具做无锁变更——否则用户看到的不是“加了个默认值”,而是“服务卡了三分钟”。


















