先SUM后ROUND更准确,因仅一次舍入;先ROUND后SUM则每项独立舍入,偏差叠加致结果偏差。MySQL与PostgreSQL的ROUND默认行为差异会加剧不一致,应统一策略并避免在聚合内使用ROUND。

先 SUM 后 ROUND 与先 ROUND 后 SUM 的误差来源完全不同
根本区别在于:前者只做一次舍入,后者对每个原始值都做一次舍入,而每次舍入都会引入独立偏差。这些偏差在加总时可能放大、抵消或随机叠加,最终导致结果不一致。
ROUND(price, 2) 放在 SUM 外层是常规做法,放在内层是危险操作
常见错误写法:SELECT SUM(ROUND(price, 2)) FROM sales。它会让每行 price 都被四舍五入一次,再相加——相当于把“账单打印前的 rounding”提前到了“记账环节”,业务逻辑就乱了。
- 假设三笔金额为
1.235、2.345、3.455(单位:元) -
SUM(price)=7.035→ROUND(7.035, 2)=7.04 -
SUM(ROUND(price, 2))=1.24 + 2.35 + 3.46=7.05 - 差值虽小(0.01),但在千条记录以上时,偏差可能达数元甚至更多
MySQL 和 PostgreSQL 对 ROUND 的默认行为差异会加剧这种不一致
比如 ROUND(2.5, 0) 在 MySQL 中返回 3,在 PostgreSQL 中可能返回 2(银行家舍入)。如果两套系统分别用“先 ROUND 后 SUM”,连中间舍入结果都不同,最终聚合自然对不上。
- 跨库迁移或双写场景下,必须统一舍入策略,不能依赖数据库默认
- 推荐显式使用
ROUND(col, 2),且避免省略第二参数 - 若需强一致性,可改用
TRUNCATE(col, 2)(MySQL)或CAST(col AS DECIMAL(10,2))(通用)替代 ROUND
DECIMAL 字段也不能完全免疫,关键看 ROUND 执行时机
即使 price 是 DECIMAL(10,4),只要在聚合前加了 ROUND(),就等于主动丢精度。SUM 本身对 DECIMAL 是精确计算,但 ROUND 是人为引入的截断点。
- 正确姿势:
SUM(price)得到精确和,最后ROUND(SUM(price), 2)仅用于展示或导出 - 错误姿势:
SUM(ROUND(price, 2))或AVG(ROUND(price, 2))—— 把舍入当成数据清洗步骤,实则是污染源 - 特别注意 CTE 或子查询中若用了 ROUND,后续再聚合,误差已不可逆


















