alter table add column 必须严格按顺序书写:字段名、数据类型、not null(如有)、default值(如有)、位置子句(first/after),顺序错或缺类型即报error 1064;text/blob不可设default(8.0.13+除外);加not null字段必须配default或分步操作。

ALTER TABLE ADD COLUMN 语法必须写对顺序
MySQL 添加字段用 ALTER TABLE ... ADD COLUMN,但字段位置、数据类型和约束的书写顺序错一点就报错。比如把 NOT NULL 放在 DEFAULT 前面,或者漏掉数据类型,MySQL 会直接拒绝执行。
常见错误现象:ERROR 1064 (42000): You have an error in your SQL syntax 或 ERROR 1101 (42000): BLOB/TEXT column 'xxx' can't have a default value(对 TEXT 类型加了 DEFAULT)。
- 基本格式:
ALTER TABLE table_name ADD COLUMN column_name data_type [NOT NULL] [DEFAULT value] [COMMENT 'xxx'] - 如果要加到表首,用
FIRST;加到某列后,用AFTER existing_column - TEXT / BLOB 类型不能设
DEFAULT(除非是 MySQL 8.0.13+ 且用空字符串或 NULL) - 添加带默认值的字段时,旧数据行会自动填充该默认值(注意大表可能锁表时间长)
添加字段前先确认存储引擎和版本兼容性
不是所有 MySQL 版本都支持在线加字段。5.6 开始 InnoDB 支持 ALGORITHM=INPLACE,但某些组合(如加 NOT NULL 且无默认值)仍会触发表拷贝。MySQL 5.7 默认允许,8.0 更宽松,但 MyISAM 引擎全程锁表。
执行前建议查一下:SELECT ENGINE, VERSION() FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'your_db' AND TABLE_NAME = 'your_table';
- 生产环境务必在低峰期操作,尤其是千万级以上的表
- 用
ALTER TABLE ... ALGORITHM=INPLACE, LOCK=NONE显式声明(MySQL 5.6.17+),失败时会立刻报错,而不是静默降级 - 如果提示
LOCK=NONE is not supported,说明当前操作不支持无锁,得换策略(比如用 pt-online-schema-change)
给已有数据的表加 NOT NULL 字段必须提供默认值或允许 NULL
这是最常踩的坑:直接写 ADD COLUMN status TINYINT NOT NULL,而表里已有 100 万行数据——MySQL 不知道老记录该填什么,就会报错 ERROR 1138 (22004): Invalid use of NULL value。
- 正确做法一(推荐):先加可空字段,再用
UPDATE填值,最后MODIFY COLUMN加NOT NULL - 正确做法二:一步到位,但必须带
DEFAULT,例如ADD COLUMN status TINYINT DEFAULT 0 NOT NULL - 注意:
DEFAULT值只影响旧数据,新插入行仍需显式提供或依赖默认值 - 如果字段逻辑上「必须非空」但历史数据确实没意义,宁可先设为
NULL,后续业务补全,也不要硬塞一个魔数(比如 -1)
加字段后记得更新应用代码和 ORM 映射
DB 层改完只是第一步。Spring Boot 的 JPA 实体类、Django 的 Model、GORM 结构体,甚至手写的 DAO 查询语句,都可能因为字段缺失或类型不匹配而运行时报错或丢数据。
- 检查是否用了
SELECT *—— 加字段后它会多返回一列,某些弱类型语言(PHP、Node.js)可能意外覆盖变量 - ORM 中新增字段需同步加注解(如
@Column(name = "new_field"))或迁移脚本标记 - 如果字段有默认值,确认应用层是否需要主动写入(比如状态字段初始值由 DB 控制,还是由业务逻辑决定)
- 别忘了更新文档、建表语句快照、以及下游 ETL 或报表工具的 schema 配置
加字段看着简单,真正麻烦的是字段语义落地的一致性。比如加了个 updated_at,就得确认是数据库自动维护(用 ON UPDATE CURRENT_TIMESTAMP),还是应用层统一赋值——两边混用很容易导致时间戳错乱。











