首页/数据/SQL 速查/改列定义与改类型
变更与事务52 条

改列定义与改类型

修改列的类型/可空性/默认值:MySQL 用 MODIFY(可同时改名用 CHANGE),PostgreSQL 用 ALTER COLUMN 分动作执行。

SQL 速查数据更新于 2026-10-13

修改列定义

改类型、改可空性、改默认值属于高频而又容易出错的一类变更。MySQL 用一个语句改整个列定义,后面没写到的部分会被按缺省处理,因此漏写约束会让它悄悄消失;PostgreSQL 把这几种动作拆成独立的子句,改类型时可以给出转换表达式处理脏数据,但要留意设置非空约束前需要全表校验。

基本信息

适用平台MySQL 8.0 / PostgreSQL 12 及以上
MySQL 写法一个语句给出完整新定义,改名与改类型可合并
PostgreSQL 写法按动作拆成独立子句分别执行
转换处理PostgreSQL 可用表达式在改类型时处理脏数据
非空约束PostgreSQL 设置时通常需要先扫描校验全表

典型使用场景

  • 字段扩容:把较短的字符列改宽
  • 精度调整:把金额列的精度提升以支持更大范围
  • 约束补全:给已有列补上非空约束与默认值
  • 类型纠偏:把误存成字符的时间字段改成时间类型
  • 迁移前的结构收敛:统一两库之间的列定义

两库写法

两库写法
-- MySQL:给出完整新定义,未写的部分按缺省处理
ALTER TABLE users MODIFY COLUMN age INT NOT NULL DEFAULT 0;
ALTER TABLE users CHANGE COLUMN age user_age INT NOT NULL DEFAULT 0;   -- 改名加改类型

-- PostgreSQL:动作拆开执行
ALTER TABLE users ALTER COLUMN age SET NOT NULL;
ALTER TABLE users ALTER COLUMN age SET DEFAULT 0;
ALTER TABLE users ALTER COLUMN age TYPE integer USING age::integer;   -- 显式转换表达式

-- 收缩长度或降低精度前先检查超限数据
SELECT COUNT(*) FROM users WHERE CHAR_LENGTH(name) > 20;

-- 改类型前先在临时表上演练一遍
-- CREATE TABLE users_tmp (LIKE users INCLUDING ALL);

动作对照

动作MySQLPostgreSQL
改类型覆盖式定义整体替换单独的类型子句
改名专用语句可同时改类型重命名语句,与类型分开
设置非空在完整定义里体现单独子句,需校验现有数据
设置默认值同样在定义中给出单独的默认值子句
脏数据转换依赖严格模式报错或截断可用转换表达式逐行处理
MySQL 的覆盖式定义是这里最容易出事的地方:只想改类型却漏写非空与默认值,约束会在一次看似无害的变更中丢失。改写前把原定义完整打印出来,逐项对照。
收缩长度、降低精度这类变更要先检查数据:严格模式与宽松模式的处理方式不同,前者报错中断,后者截断写入,两种结果都需要事先预演。

易错点

  • MySQL 覆盖式定义漏写原有约束:一次改类型把非空与默认值一起丢掉
  • 收缩长度前不检查超限数据:严格执行时报错中断变更,宽松执行时数据被截断
  • PostgreSQL 设置非空约束时全表校验耗时很长,大表上要预留执行窗口
  • 改类型时缺少转换表达式,格式不合规的数据让变更失败并中断
  • 变更与代码发布不同步,新旧代码对列类型的预期不一致,出现写入失败

数据来源与参考

  • MySQL 8.0 Reference Manual · ALTER TABLE
  • PostgreSQL Documentation · ALTER TABLE
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌