MySQL修改decimal列小数精度时触发数据截断错误的原因咨询
问题解析与解决
关于报错里的“不存在行号”
别误会,报错里的row 1、row 329不是你表的主键ID,是MySQL执行ALTER时按数据物理存储顺序扫描的行计数,和业务主键完全不挂钩:
- InnoDB中数据按聚簇索引(一般是主键)顺序存储,但表经过删改操作后会产生碎片,扫描时的行号只是内部处理的计数,并非你看到的主键值。
- 执行
ALTER TABLE修改列类型时,MySQL会逐行校验数据是否符合新类型的范围,报错里的行号就是它扫到的第N行(物理顺序),不是主键为N的行。
为什么提高小数精度会触发截断?
你没搞清楚decimal(M,D)的定义规则:
M是总位数(整数部分+小数部分的总长度),D是小数部分的位数。- 原类型
decimal(20,2):总位数20,小数占2位,所以整数部分最多能存18位(20-2); - 改成
decimal(20,18)后,总位数还是20,小数占18位,整数部分只能存2位(20-18)。
如果你的列里有整数部分超过2位的值(比如100.00、12345.67),这些值根本塞不下新类型的整数位,自然触发“数据超出范围”的截断报错。改成decimal(20,16)时,整数部分最多存4位,扫到第329行(物理顺序)的数值整数位超了4位,就会报错。
解决建议
- 要保留原有整数精度同时提高小数精度,得把总位数
M也调高,比如改成decimal(38,18)(MySQL支持的最大decimal总位数是38),这样整数部分能存20位(38-18),完全容纳原来的18位整数+新增的小数位。 - 改之前可以先排查哪些数据会超标:
-- 找decimal(20,18)存不下的数据(整数≥100) SELECT column_name FROM table_name WHERE column_name >= 100; -- 找decimal(20,16)存不下的数据(整数≥10000) SELECT column_name FROM table_name WHERE column_name >= 10000;
内容的提问来源于stack exchange,提问作者Hayate
相关产品推荐
相关产品推荐

