ROUND函数n为负数时向左舍入到整数位(如-2=百位),非报错;CEIL/CEILING跨库兼容性差;ROUND+CEIL链式调用易因隐式转DOUBLE致精度丢失;货币结算需警惕银行家舍入陷阱。
ROUND 函数四舍五入时,小数位数参数为负数是什么意思
ROUND(
,
) 的第二个参数
为负数时,不是报错,而是向左对整数部分做舍入——比如
结果是
,相当于“舍到百位”。这在按千/万单位聚合、报表取整展示时很实用,但容易被当成 bug 忽略。
常见错误现象:
返回
,而不是
;因为它是先按十位舍入(即看个位),再进位。实际逻辑是:把数字除以
→ 四舍五入 → 再乘回去。
MySQL 和 PostgreSQL 行为一致;SQL Server 也支持负数,但旧版本(2005 以前)不支持
如果想“截断”而非“四舍五入”,不能用
,得用
或字符串截取
注意浮点精度问题:
在某些数据库里可能返回
而非
,这是底层二进制表示导致的,不是函数缺陷
CEIL 和 FLOOR 在不同数据库中的函数名差异
是标准 SQL 函数名,但 MySQL 早期版本只认
,PostgreSQL 全都支持,SQL Server 只支持
。写跨库 SQL 时硬写
可能直接报错
。
使用场景:计算分页总页数(
)、向上取整分配资源(如最小服务器数量)、避免因浮点除法结果略小于整数而误判为“不够”。
PostgreSQL 中
和
完全等价;MySQL 8.0+ 已支持
,但 5.7 及更早必须用
SQLite 没有原生
,得用
替代
Oracle 的
接受 NUMBER 类型,但如果传入 BINARY_FLOAT 可能触发隐式转换警告
ROUND + CEIL 混用时的隐式类型转换陷阱
当
输出作为
输入时(例如
),看似合理,但某些数据库(如老版本 Hive)会在中间步骤把 DECIMAL 转成 DOUBLE,引发精度丢失——
理论应为
,却可能算出
,再套
就变成
。
性能影响:嵌套数值函数本身开销不大,但若在 WHERE 或 ORDER BY 中大量使用,会阻止索引下推,尤其在分区表上可能触发全表扫描。
优先用 DECIMAL 类型字段参与运算,避免用 FLOAT/DOUBLE 存储金额
如果必须链式调用,PostgreSQL 可显式转回 numeric:
MySQL 5.7+ 推荐用
中断隐式转换链
处理货币计算时,为什么别用 ROUND 做最终结算
银行或支付系统要求“结算值 = 原始值 × 汇率后,按币种规则四舍五入”,但
默认使用“四舍六入五成双”(银行家舍入),而多数业务要求“传统四舍五入”。MySQL 8.0+ 的
是传统四舍五入,但 PostgreSQL 默认是银行家舍入,SQL Server 则取决于 NUMERIC 精度定义。
容易踩的坑:前端传
过来,后端用
存库,结果存成
(银行家舍入)而非预期的
,对账时差 1 分钱。
PostgreSQL 若需传统四舍五入,改用
并确保输入是 numeric 类型(text 或 float 会触发银行家规则)
涉及多币种结算,建议在应用层做最后舍入,数据库只存高精度中间值
审计关键字段时,宁可多存一列
,也不依赖 SELECT 时动态
数值精度问题从来不是单个函数能兜住的,它横跨数据类型定义、传输格式、数据库配置和业务规则四层。少一个环节对齐,就可能在月底对账时突然冒出来。
valuennROUND(1234.56, -2)1200ROUND(999.99, -1)100099010^ABS(n)ROUNDFLOORROUND(1.235, 2)1.231.24CEILCEILINGCEILINGCEILInvalid function name 'CEIL'CEILING(total_count / page_size)CEILCEILINGCEILCEILINGCEIL-FLOOR(-x)CEILROUNDCEILCEIL(ROUND(price * 1.08, 2))ROUND(199.99 * 1.08, 2)215.99215.98999999999998CEIL216CEIL(ROUND(x * 1.08, 2)::numeric)CAST(ROUND(...) AS DECIMAL(10,2))ROUNDROUND100.5ROUND(x, 0)100101ROUND(x::numeric, 0)amount_roundedROUND