MySQL的ROUND()默认采用银行家舍入(四舍六入五成双),非传统四舍五入;严格四舍五入需用FLOOR(x+0.5)(正数)或ROUND(x+SIGN(x)*0.5-0.5)(通用);DECIMAL类型可保精度,FLOAT/DOUBLE易因浮点误差失准。

ROUND() 怎么用才不丢精度
MySQL 的 ROUND() 默认是「四舍六入五成双」(银行家舍入),不是小学数学里的四舍五入。比如 ROUND(2.5) 得 2,ROUND(3.5) 得 4——这容易让人误以为算错了。
- 要严格四舍五入到整数,直接用
ROUND(x, 0)即可,但得接受银行家规则 - 想强制「传统四舍五入」,得绕一下:
FLOOR(x + 0.5)(仅适用于正数);负数要用CEIL(x - 0.5),更稳妥写法是ROUND(x + SIGN(x) * 0.5 - 0.5) - 小数位控制必须显式传第二个参数,
ROUND(123.456)和ROUND(123.456, 0)效果一样,但ROUND(123.456, 2)才得 123.46 -
ROUND()对 DECIMAL 类型最准,对 FLOAT/DOUBLE 可能因浮点误差导致意外结果,比如ROUND(1.235, 2)有时返回 1.23 而非 1.24
CEIL() 和 FLOOR() 不是四舍五入,别混用
CEIL() 是向上取整,FLOOR() 是向下取整,它们和四舍五入无关,只是边界操作。常见错误是以为 CEIL(x - 0.5) 就等于四舍五入——它在负数上会崩。
-
CEIL(2.1)→ 3,CEIL(-2.1)→ -2(注意:-2 比 -2.1 大) - 想实现「向零取整」,用
TRUNCATE(x, 0),不是CEIL/FLOOR - 做分页计算时常用
CEIL(total / page_size),但要注意total和page_size都是整数,否则除法结果可能带小数,触发隐式类型转换 - 在 GROUP BY 或聚合中用
CEIL()要小心,它不能直接用于窗口函数的 ORDER BY 子句(MySQL 8.0+ 支持,但低版本报错Invalid use of group function)
ROUND() 的精度陷阱:DECIMAL vs FLOAT
如果你的字段是 FLOAT 或 DOUBLE,ROUND() 的结果可能和预期不符,根本原因在于浮点数无法精确表示十进制小数。
- 执行
SELECT ROUND(0.295, 2);,可能得到 0.29 而不是 0.30——因为 0.295 在二进制里是无限循环小数,实际存的是略小的值 - 解决方案:先把值转成
DECIMAL,比如ROUND(CAST(0.295 AS DECIMAL(10,3)), 2) - 建表时,金额、百分比、统计指标这类需要确定精度的字段,务必用
DECIMAL(M,D),别图省事用FLOAT -
ROUND()第二个参数支持负数,ROUND(1234.56, -2)→ 1200,但负精度对FLOAT字段同样不稳定
替代方案:用 FORMAT() 或自定义函数?
FORMAT() 看似能四舍五入并加千分位,但它返回的是字符串,没法参与后续数值计算,纯属展示用途。
-
FORMAT(1234.567, 2)返回'1,234.57',再套CAST(... AS DECIMAL)会失败或丢失逗号 - 真有复杂舍入逻辑(如按区间舍入、保留有效数字),建议在应用层处理,MySQL 函数能力有限且不易调试
- 如果必须数据库内解决,可用
ELT()+MOD()拼条件,但可读性差、维护成本高,不如换语言 - MySQL 8.0+ 支持 CTE 和窗口函数,但没提供
ROUND_HALF_UP这类明确语义的函数,别指望靠升级版本绕过精度问题
真正麻烦的不是函数怎么写,而是你不知道字段底层存的是近似值还是精确值。查 SHOW COLUMNS FROM table_name 确认类型,比背函数手册重要得多。











