sql 四舍五入为什么 2.5 变成 2?nearest even 规则、负 scale 与整数除法截断
数据库里做四舍五入,最常遇到三类怪事:算出来直接是 0、2.5 变成 2、以及想保留两位却多出一串尾数。前两个分别源于整数除法截断与"就近取偶"规则,第三个是浮点类型本身的问题。本文依据 PostgreSQL 官方数学函数文档原文整理。

一、先分清四个取整函数
PostgreSQL 数学函数页(该地址可正常访问)对四者的定义分别是:ceil 与 ceiling 为 "Nearest integer greater than or equal to argument",floor 为 "Nearest integer less than or equal to argument",trunc 原文标注 "(truncates towards zero)",round 则是 "Rounds to nearest integer"。区别在负数上最明显:ceil(-42.8) 得 -42,floor(-42.8) 得 -43,trunc(-42.8) 得 -42。把 trunc 当 floor 用,在负数区间就会错。
二、第一个坑:整数相除先截断
这是"乘 100 再除还是 0"的根因。官方说明原文:"Division (for integral types, division truncates the result towards zero)"。也就是两个整数相除,小数部分在进入 round 之前就已经丢失:
SELECT round(1 / 3 * 100, 2); 结果为 0.00,因为 1 / 3 已经是 0。
正确写法是把任一侧转成精确小数:
SELECT round(100.0 * numerator / denominator, 2);SELECT round(numerator::numeric / denominator, 4);
三、round 有两个重载,返回类型不同
文档给出 round ( numeric ) → numeric 与 round ( double precision ) → double precision。这决定了精度上限:double precision 是二进制浮点,存不下 0.1 这样的十进制小数,所以对它取整仍可能看到尾数异常;而 numeric 是十进制精确类型。官方示例 round(42.4) → 42。
四、第二个坑:2.5 为什么进位到 2
文档在 round 的说明里直接写出规则名称:"round to nearest even" is the most common rule,即"四舍六入五取偶"的银行家舍入。效果是 round(2.5) 得 2、round(3.5) 得 4,因为都取到最近的偶数。财务对账时若期望"逢五必进",用默认 round 就会与手工核算不上。
需要传统进位时,不要指望函数参数,常见做法是显式加半个最小单位再取整,或改用 trunc(x * 100 + 0.5) / 100 这类表达式;务必先确认所用数据库对哪种类型采用哪种规则,并实测一组含 0.5 边界的数据。
五、scale 参数与负 scale 的妙用
双参形式 round ( v numeric, s integer ) → numeric 的官方示例极具价值:round(42.4382, 2) → 42.44,round(1234.56, -1) → 1230。第二个参数可以为负,-1 表示十位取整、-2 表示百位取整。做报表分档、区间统计时,负 scale 比先除后乘再取整可靠得多,也不会踩整数截断。
文档另有 min_scale,定义为 "Minimum scale (number of fractional decimal digits) needed to represent the supplied value precisely",示例 min_scale(8.4100),用来判断数值真实需要几位小数。
六、跨库差异与金额的正确姿势
各家规则不同:MySQL 的 ROUND 对 DECIMAL 采用远离零的进位,SQL Server 的精度行为依表达式类型而定。所以统一原则是:金额一律用 DECIMAL/NUMERIC 存储与运算,不用 FLOAT/DOUBLE;比率计算显式转 numeric;最后展示层才做一次取位。另外 numeric(10,2) 这类 precision 与 scale 声明会限制总位数,超范围会报错而非静默截断。
七、常见问题 FAQ
问:为什么百分比全为 0?
答:整数除法已截断,先把分子或分母转成带小数的类型再运算。
问:取两位后还有很长的尾数?
答:多为 double 参与运算,改用 numeric 并对结果显式取整。
问:想要强制进位怎么办?
答:用表达式实现远离零进位,不要依赖默认 round 的规则。
八、总结
SQL 四舍五入的完整认知是:四个取整函数中只有 round 是就近取整,ceil 与 floor 按方向、trunc 向零截断;整数除法会先截断小数,比率计算必须显式转 numeric;round 对 numeric 与 double 各有重载且精度表现不同;默认规则是 nearest even,逢五取偶,与手工四舍五入不一致;scale 可为负,-1 即十位取整;金额用 DECIMAL 存储、展示层再取位,并实测 0.5 边界。结果对不上时,先查是不是整数除法,再查是不是取偶规则。
生产内容,同时打通搜索引擎(SEO)与AI搜索引擎(GEO)流量入口的软件! 点击进入365建站器 »
