ROUND采用银行家舍入(如ROUND(2.5)→2),TRUNC为硬截断(如TRUNC(-123.999,1)→-123.9),二者负精度含义相同但结果迥异(如ROUND(1234.567,-2)→1200,TRUNC(1234.567,-2)→1200)。
ROUND 和 TRUNC 在 Oracle 中根本不是为“处理浮点数”而设计的通用类型操作函数——它们只作用于数值表达式,且行为差异极关键。选错一个,财务对账或统计汇总就可能出偏差。
ROUND 是四舍五入,但默认用银行家舍入法
很多人以为 round(1.5) 一定得 2、round(2.5) 一定得 3,其实 oracle 默认采用“向偶数舍入”(banker’s rounding):小数部分恰好为 0.5 时,往最近的偶数靠。
-
ROUND(1.5)→ 2(1 和 2 中,2 是偶数) -
ROUND(2.5)→ 2(2 和 3 中,2 是偶数) -
ROUND(3.5)→ 4(3 和 4 中,4 是偶数)
这种行为在金融场景中是合规的,但若业务明确要求“无条件向上进位”,就不能依赖 ROUND;此时应改用 CEIL 或手动加 0.5 后 FLOOR。
TRUNC 是硬截断,不看小数大小
TRUNC 完全不参与任何舍入逻辑,它只是按位“砍掉”,连符号都不影响:
-
TRUNC(123.999, 1)→ 123.9(不是 124.0) -
TRUNC(-123.999, 1)→ -123.9(不是 -124.0) -
TRUNC(89.985, -1)→ 80(小数点左边第 1 位是十位,“89”被截成“80”)
注意:TRUNC(x, -n) 截的是整数高位,不是四舍五入。当 n 大于数字总位数时(如 TRUNC(89, -3)),结果为 0 —— 这点容易被忽略,导致聚合后突然出现零值。
ROUND 和 TRUNC 的负精度参数含义一致但结果迥异
两者都支持负的 decimals 参数,表示对小数点左侧第 |n| 位进行操作,但语义完全不同:
-
ROUND(1234.567, -2)→ 1200(四舍五入到百位:1234.567 百位是 2,千位是 1,后面 34.567 -
TRUNC(1234.567, -2)→ 1200(直接抹掉十位和个位,不判断) -
ROUND(1278.5, -2)→ 1300(34.567 变成 78.5,≥50 → 进位) -
TRUNC(1278.5, -2)→ 1200(照样抹掉,78.5 被丢弃)
也就是说:负精度下,ROUND 仍会进位,TRUNC 永远只截。做金额分档(如“万元单位取整”)时,必须确认业务要的是“近似值”还是“向下归整”。
日期场景下,TRUNC 常被误当作 ROUND 用
对日期使用 TRUNC(sysdate) 得到当天 00:00:00,这是安全的;但若写成 ROUND(sysdate),Oracle 会按“中午 12 点”为界做四舍五入:
- 当天 11:59:59 →
ROUND后仍是当天 00:00:00 - 当天 12:00:00 →
ROUND后变成次日 00:00:00
这个行为在报表周期切分、数据分区边界计算中极易引发漏数或重复计数。尤其当你的 SQL 里混用了 TRUNC 和 ROUND 处理同一时间字段时,务必统一——不要指望“差不多”。
ROUND 和 TRUNC 在负精度、临界值、负数、日期上下文中的输出可能完全错开一个量级。调试时别只看正数示例,一定要覆盖边界值、负数、高位截断这三类 case。











