MySQL的ROUND()默认采用“四舍六入五成双”(银行家舍入),非传统四舍五入;如需后者,应使用ROUND(x + SIGN(x) * 0.5 - 0.5)并配合DECIMAL类型规避浮点误差。

MySQL的ROUND()默认不是“四舍五入”,而是“四舍六入五成双”(银行家舍入),直接写ROUND(x, 2)可能在临界值上出错,比如ROUND(2.5, 0)得2而非3。真要传统四舍五入,得绕一下。
ROUND(x, d) 的小数位控制必须显式传参
省略第二个参数等价于ROUND(x, 0),仍走银行家规则;想保留两位小数,必须写ROUND(x, 2)。负数精度也有效:ROUND(1234.56, -2) → 1200,但对FLOAT列效果不稳定。
常见错误现象:
-
SELECT ROUND(1.235, 2)有时返回1.23而不是1.24——根本原因是1.235在二进制中无法精确表示,实际存储值略小于1.235 -
ROUND(price)和ROUND(price, 0)行为一致,但容易让人误以为“不写参数就更‘原始’”,其实没区别
严格传统四舍五入的写法(含正负数)
别用FLOOR(x + 0.5),它在负数上失效(如FLOOR(-1.6 + 0.5) = FLOOR(-1.1) = -2,但期望是-2没错?等等——-1.6传统四舍五入应为-2,而-1.4应为-1,所以FLOOR(x + 0.5)对负数其实偶然成立,但不通用。
稳妥写法是:ROUND(x + SIGN(x) * 0.5 - 0.5)
使用场景:
MySQL 数据库管理技能,能够通过自然语言查询和管理数据库,支持 SELECT/INSERT/UPDATE/DELETE、表管理、备份恢复等操作。当用户提及 MySQL、数据库查询、建表或数据备份时使用此技能。
- 财务报表导出要求“小学数学规则”,不能接受银行家舍入 该表达式在
- 配合
CAST(... AS DECIMAL(10,2))可进一步规避浮点误差
x = 0时安全(SIGN(0)返回0,整体为ROUND(-0.5) → 0)DECIMAL字段里ROUND没反应?先查插入时是否已被截断
建表定义price DECIMAL(10,2),插入9.995后查出来就是9.99——这不是ROUND()的问题,是DECIMAL类型在INSERT时就按定义精度**直接截断**(非舍入),且不可逆。
实操建议:
- 插入前用
ROUND(原始值, 2)处理,再存入DECIMAL(10,2) - 若需中间计算留余量,字段定义放宽:比如预期存2位小数,设为
DECIMAL(10,4),最后查询时再ROUND(col, 2) - 用
SHOW COLUMNS FROM table_name确认字段真实定义,别只信业务文档
GROUP BY 或 ORDER BY 中用 ROUND 容易分组错乱
对DOUBLE类型字段直接ROUND(price, 1) GROUP BY,可能导致本该归为同一组的1.15和1.1499999999999999被拆开——因为后者实际二进制表示略小,ROUND()后变成1.1而非1.2。
解决方案:
- 优先转类型:
ROUND(CAST(price AS DECIMAL(10,3)), 1) - 或放大取整再缩回:
ROUND(price * 10) / 10(比ROUND(price, 1)抗浮点误差) - 调试时加一列看原始精度:
SELECT price, BIN(price), ROUND(price, 1) FROM t LIMIT 5
最易被忽略的一点:ROUND的行为高度依赖输入值的底层类型。同一条SQL,在DECIMAL列上稳定,在FLOAT列上可能每次执行结果都不同——别把精度问题甩锅给函数本身,先盯住数据怎么来的、存在哪、怎么算的。










