group by 后 sum() 出现 0.1 + 0.2 ≠ 0.3 是因浮点数二进制表示精度限制,属 ieee 754 标准固有现象;应使用 round(sum(col), 2) 控制小数位,避免在 where 中直接等值比较浮点聚合结果。

GROUP BY 后 SUM() 出现 0.1 + 0.2 ≠ 0.3 这种小数误差
浮点数在二进制中无法精确表示十进制小数,SUM() 聚合后直接展示或参与比较时,常出现 0.30000000000000004 这类值。这不是 SQL 的 bug,而是 IEEE 754 标准的固有表现。
实操建议:
- 聚合后立刻用
ROUND(<code>SUM(col), 2) 控制小数位,比如钱、重量等业务场景通常只需两位 - 不要在
WHERE中直接写SUM(col) = 0.3—— 改成ABS(SUM(col) - 0.3) 或先 <code>ROUND再比较 - 如果字段本身是金额,建表时优先用
DECIMAL(10,2)而非FLOAT或DOUBLE,从源头避免问题
ROUND 函数在不同数据库里的行为差异
ROUND() 看似简单,但 MySQL、PostgreSQL、SQL Server 对负数、边界值(如 0.5)的处理不一致,尤其跨库迁移时容易出错。
实操建议:
- MySQL 默认“四舍五入”,
ROUND(2.5)→3;但 PostgreSQL 在某些版本对 .5 采用“银行家舍入”(偶数优先),ROUND(2.5)→2 - 想强制统一行为,避免依赖默认:显式加
ROUND(col, 2)指定位数,别省略第二个参数 - SQL Server 的
ROUND(2.5, 0)返回3.0(带小数点),而 MySQL 返回整数3,后续做字符串拼接或前端渲染时可能意外多出.0
GROUP BY + ROUND 组合导致分组结果“消失”或重复
把 ROUND() 直接放进 GROUP BY 子句,比如 GROUP BY ROUND(price, 1),看似能归并相近价格,实际会因浮点计算时机和精度截断,让本该同组的值被拆开。
实操建议:
- 分组逻辑应基于原始语义字段(如商品类别、日期),而不是靠
ROUND()“凑”分组依据 - 真需要按价格区间聚合,用
CASE WHEN或FLOOR(price * 10) / 10更可控,比如FLOOR(price * 10)得到十分位整数,再除回 - 如果必须用
ROUND()分组,确保所有参与运算的字段都是DECIMAL类型,避免隐式转为FLOAT引入额外误差
ROUND 不能解决所有精度问题,尤其涉及中间计算
比如 ROUND(AVG(col), 2) 看似安全,但如果 col 是 FLOAT,平均过程已累积误差;又或者先 SUM 再 ROUND,再除以计数,和先 ROUND 每行再 SUM 结果不同。
实操建议:
- 精度敏感场景(财务、计费),全程用
DECIMAL,连临时变量、CTE 中的列也显式CAST(... AS DECIMAL(12,2)) - 避免链式浮点操作:
ROUND(SUM(a/b), 2)不如先ROUND(a, 2)/ROUND(b, 2)(视业务是否允许) - 测试时别只看最终显示值,用
CAST(col AS CHAR)查看完整存储值,确认误差发生在哪一步
ROUND 是个开关,不是保险箱。真正决定精度上限的,是字段类型、计算顺序和数据库对数值类型的底层实现。漏掉其中一环,ROUND 再多也盖不住。










