MySQL的CHANGE需重写完整列定义,PostgreSQL用RENAME COLUMN+ALTER COLUMN TYPE分步操作,SQLite须手动重建表。

MySQL 里用 ALTER TABLE ... CHANGE 改列名会连带改类型
这个指令不是“只改名字”,它本质是先删掉旧列、再按新定义加一列,所以哪怕你只写了个新列名,没动类型,MySQL 也会按你写的完整定义重建——这意味着默认值、是否允许 NULL、字符集、排序规则全得重新声明,漏了就变默认行为。
常见错误现象:ERROR 1060 (42S21): Duplicate column name 'xxx'(写错新列名和旧列名一样)、ERROR 1054 (42S22): Unknown column 'old_name' in 'table definition'(表名或旧列名拼错)、或者改完发现 NOT NULL 没了、DEFAULT 变成 NULL。
- 必须同时写出旧列名、新列名、**完整数据类型**(比如
VARCHAR(255)不能省成VARCHAR) - 如果原列有
NOT NULL,新定义里也得显式写上,否则默认变成允许NULL - 如果原列有
DEFAULT值,新定义里不写,这个默认值就丢了 - 字符字段要留意
CHARACTER SET和COLLATE,不指定就按表默认走,可能和原来不一致
示例:把 user_name 改成 username,保持 NOT NULL 和默认值:
ALTER TABLE users CHANGE user_name username VARCHAR(100) NOT NULL DEFAULT '';
PostgreSQL 不支持 CHANGE,得用 RENAME COLUMN + ALTER COLUMN TYPE 分开操作
PostgreSQL 没有 CHANGE 这个语法,强行套用会报错:ERROR: syntax error at or near "CHANGE"。它把“改名”和“改类型”拆成两个独立动作,更安全,也更明确。
使用场景:当你只想改列名,类型完全不变;或者想先改名、再单独调精度/长度/约束。
- 只改名用
RENAME COLUMN,不碰类型、约束、默认值,原样保留 - 要改类型(比如
INT→BIGINT),必须额外执行ALTER COLUMN ... TYPE,且可能需要USING子句做转换 - 改类型时如果存在数据,PostgreSQL 会检查能否隐式转换,不行就报错,不会静默截断
示例:改名 + 后续扩类型
ALTER TABLE users RENAME COLUMN user_name TO username;<br>ALTER TABLE users ALTER COLUMN username TYPE VARCHAR(255);
CHANGE 在 MySQL 5.7+ 和 8.0 的行为一致,但要注意 ONLY_FULL_GROUP_BY 等 SQL mode 影响间接执行
指令本身在版本间没变化,但如果你的语句里涉及函数、表达式或依赖隐式转换,而当前 SQL mode 开了 STRICT_TRANS_TABLES 或 ONLY_FULL_GROUP_BY,就可能在执行中卡住——不是语法错,而是数据校验失败。
性能影响:对大表执行 CHANGE 会锁表(MySQL 5.6 及以前是 copy table 方式,8.0 多数 DDL 支持 inplace,但 CHANGE 仍需重建列,不是纯元数据操作)。
- 线上大表慎用,建议在低峰期执行,提前评估耗时(可先在从库试)
- 如果只是改注释,别用
CHANGE,用MODIFY COLUMN ... COMMENT更轻量 - 备份好数据,
CHANGE不支持事务回滚,执行即生效
SQLite 完全不认 CHANGE,改列名只能靠重建表
SQLite 把 ALTER TABLE 限制得很死:只支持 RENAME TO(改表名)和 ADD COLUMN。改列名?没有直接语法。你得手动建新表、导数据、删旧表、重命名——整个过程得自己保证约束、索引、触发器不丢。
容易踩的坑:忘了 PRIMARY KEY 或 UNIQUE 约束,导完数据后查重失败;或者没重建索引,查询突然变慢;还有外键开启时,PRAGMA foreign_keys = ON 下重建表可能被阻止。
- 先
CREATE TABLE new_table AS SELECT old_col AS new_col, ... FROM old_table(仅适用于简单场景) - 更稳妥的是用
CREATE TABLE显式定义新结构,再INSERT INTO ... SELECT - 记得用
PRAGMA foreign_keys = OFF临时关外键检查,操作完再开 - 用
.schema查原表结构,避免漏掉NOT NULL或默认值

















