ROUND() 默认采用“四舍六入五成双”(银行家舍入),非传统四舍五入;如 ROUND(2.5,0)得2、ROUND(1.235,2)可能得1.23;负精度舍入逻辑易误解,建议用FLOOR/CEIL替代;真需四舍五入宜用ROUND(x*100)/100或IF(x>=0,FLOOR(x+0.5),CEIL(x-0.5));DECIMAL字段插入前须显式ROUND,否则INSERT时直接截断;WHERE中禁用ROUND等值比较,应改用范围查询。

ROUND() 默认不是你想要的“四舍五入”,而是“四舍六入五成双”(银行家舍入)。直接写 ROUND(2.5, 0) 得到的是 2,不是 3;ROUND(1.235, 2) 有时返回 1.23 而非 1.24——这不是 bug,是设计如此,但业务上常不能接受。
ROUND(x, d) 必须显式传小数位数,省略参数不等于“更原始”
不写第二个参数等价于 ROUND(x, 0),依然走银行家规则。想保留两位小数,必须写 ROUND(x, 2);想对百位取整,写 ROUND(x, -2),但要注意这是“向左舍入”,不是“保留百位数字”。
常见错误现象:ROUND(1450, -2) 返回 1400(因 14 是偶数,按规则不进),而 ROUND(1499, -2) 返回 1500。这种行为在业务中缺乏可解释性。
- 负数精度慎用,建议改用
FLOOR(x / 100) * 100或CEIL(x / 100) * 100,逻辑清晰且可控 -
d为负数时,输入为NULL仍返回NULL,但若表达式含隐式类型转换(如拼接字符串),可能意外报错 - 对
DOUBLE字段直接ROUND(col, 1),底层二进制误差会导致本该同组的值被拆开(如1.15和1.1499999999999999)
真要传统四舍五入,别依赖 ROUND 的默认行为
正数可用 FLOOR(x + 0.5):安全、简洁、无歧义;负数需单独处理,否则 FLOOR(-1.6 + 0.5) → FLOOR(-1.1) → -2,虽结果碰巧对,但逻辑不可靠。
通用写法(兼容正负零):IF(x >= 0, FLOOR(x + 0.5), CEIL(x - 0.5))。注意:若 x 是 DECIMAL,加 0.5 前最好先 CAST(x AS DECIMAL(12,3)),避免隐式转 DOUBLE 引入误差。
- 更常用且抗误差的写法:
ROUND(x * 100) / 100(放大→取整→缩回),本质强制触发数学四舍五入 - 配合
CAST(... AS DECIMAL(10,2))可进一步规避浮点表示问题 - 不要用
FLOOR(x + 0.5)处理未校验的DOUBLE列,原始值可能已是近似值
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确认字段真实定义,别只信文档或印象
WHERE 条件里禁用 ROUND 做等值比较
写 WHERE ROUND(price, 2) = 19.99 会阻止索引下推,且因银行家规则或浮点误差,可能查不到物理值为 19.985 的记录(ROUND(19.985, 2) 在某些版本返回 19.98)。
- 正确做法:用范围代替,如
price >= 19.985 AND price < 19.995 - 该写法既可走索引,语义也更准确(表达“落在 19.99 所代表的区间内”)
- 如果必须在 WHERE 中做精度判断,优先用
CAST(price AS DECIMAL(10,3))再运算,减少 double 误差干扰
真正难的不是怎么调 ROUND(),而是从建表开始就明确:金额字段必须用 DECIMAL,中间计算要留足精度余量,而“四舍五入”这个动作,到底该发生在应用层、SQL 查询层,还是存储层——三者选错位置,后面所有 ROUND 都白写。


















