round函数在不同数据库中行为差异大:mysql 8.0+支持三参数(含截断),postgresql默认四舍五入但需trunc实现截断,sql server第三参数非0即截断;oracle等可能用银行家舍入,金融计算须显式控制逻辑。

ROUND函数在不同数据库中的行为差异
MySQL、PostgreSQL 和 SQL Server 的 ROUND 默认四舍五入,但 Oracle 和某些旧版 SQL Server 在遇到 .5 时可能采用“银行家舍入”(四舍六入五成双),实际结果未必是你预期的“进一”。比如 ROUND(2.5, 0) 在 PostgreSQL 返回 3,在 Oracle 可能返回 2。
实操建议:
- 不要依赖默认行为做金融计算,显式指定舍入逻辑更安全
- MySQL 8.0+ 支持
ROUND(x, d, f)第三个参数f:0=四舍五入(默认),1=向下取整,2=向上取整,3=截断(类似 TRUNC) - PostgreSQL 中
ROUND始终四舍五入,如需截断请用TRUNC或FLOOR/CEIL - SQL Server 的
ROUND第三个参数为 0(默认)时四舍五入,非 0 时截断(注意:不是向下取整!是直接砍掉小数位)
TRUNC函数不等于INT或FLOOR
TRUNC 是“截断”,不是“向下取整”。TRUNC(-3.7, 0) 得到 -3,而 FLOOR(-3.7) 是 -4。这点在处理负数金额、温度、坐标等场景极易出错。
常见错误现象:
- 用
TRUNC(salary / 1000)计算千位工资段,结果发现 -5800 元被归到 -5 千而不是 -6 千 - 误以为
TRUNC(x, 2)等价于CAST(x AS DECIMAL(10,2))—— 后者可能触发四舍五入,前者一定不进位 - Oracle 和 PostgreSQL 支持
TRUNC(datetime)截日期,但 MySQL 没有该用法,得用DATE()或STR_TO_DATE()
ROUND与TRUNC混用时的精度陷阱
嵌套使用 ROUND 和 TRUNC 容易放大浮点误差。例如先 TRUNC(price * 100) 再除以 100,看似保留两位小数,但 price 若为浮点类型(如 REAL 或 FLOAT),中间乘法已引入不可见误差,TRUNC 只是把错误“固定”下来。
使用场景建议:
- 货币运算一律用
DECIMAL类型存储,避免浮点参与舍入 - 需要“显示两位小数但不四舍五入”时,优先用
TRUNC(value * 100) / 100.0,而非ROUND(value, 2) - 若数据库不支持
TRUNC(如早期 SQLite),可用CAST(FLOOR(value * 100) AS REAL) / 100模拟,但注意负数需改用CEIL
跨数据库可移植的舍入写法
没有一行 SQL 能在所有数据库中语义一致地实现“截断到小数点后两位”。最稳妥的方式是把舍入逻辑下沉到应用层,或在 SQL 层做数据库适配。
可操作方案:
- MySQL:用
ROUND(x, 2, 3)(第三个参数 3 表示截断) - PostgreSQL:用
TRUNC(x, 2) - SQL Server:用
ROUND(x, 2, 1)(第三个参数非 0 即截断) - Oracle:用
TRUNC(x, 2) - 如果必须写通用 SQL,且只处理正数,可用
FLOOR(x * 100) / 100.0;负数则需加条件判断,复杂度陡增
真正容易被忽略的是:很多 BI 工具(如 Tableau、Power BI)会在查询后端再做一次舍入,导致 SQL 层的结果被二次加工。调试时务必确认舍入发生在哪一层。











