直接对聚合结果用round(sum(...), n)是安全的,先round再sum会因每行单独四舍五入导致加总偏差,如三笔1.235金额,前者得3.71、后者得3.72,财务场景不可接受。

直接对聚合结果用 ROUND(SUM(...), n) 是安全的,但先 ROUND 再 SUM 会引入偏差——这是最常踩的坑。
为什么不能写 SUM(ROUND(amount, 2))?
每行单独四舍五入后再加总,和先加总再四舍五入,结果可能不一致。比如三笔金额:1.235、1.235、1.235。
-
SUM(ROUND(amount, 2))→ROUND(1.235,2)=1.24×3 =3.72 -
ROUND(SUM(amount), 2)→ROUND(3.705, 2)=3.71
差值虽小,但在财务对账或报表汇总中不可接受。MySQL、PostgreSQL、SQL Server 全部如此,不是 bug,是数学必然。
ROUND(SUM(...), n) 的参数和类型陷阱
第二个参数 n 必须是整数表达式,不能是浮点变量(Oracle 会报 ORA-01722);结果类型继承自输入字段——如果 amount 是 DECIMAL(12,3),ROUND(SUM(amount), 2) 仍可能返回 123.450 而非 123.45。
- 显式截断尾随零:
CAST(ROUND(SUM(amount), 2) AS DECIMAL(10,2)) - 避免浮点误差:原始字段别用
FLOAT,优先用DECIMAL存储 - MySQL 5.7+ 和 PostgreSQL 对
DECIMAL输入更稳定;SQL Server 需注意其默认银行家舍入规则
在 GROUP BY 中对聚合值四舍五入要小心什么?
写 GROUP BY ROUND(price, 1) 看似方便,但 1.249 和 1.251 都变成 1.2,分组逻辑就变了——这不是函数问题,是舍入压缩了精度区间。
- 若目标是“按 0.1 元档位统计”,建议用范围分组:
CASE WHEN price - 若必须用
ROUND分组,确认业务能接受这种精度合并 - 别在
WHERE里写ROUND(SUM(...), 2) = 100——索引失效,改用范围:SUM(...) BETWEEN 99.995 AND 100.004999
真正难的不是语法,而是判断:这个四舍五入是给用户看的,还是参与后续计算的?前者可以宽松,后者必须从源头控制类型和精度。










