整数除法是什么
除法的结果类型是跨库高频差异点:MySQL 里 5 / 2 得到 2.5000 这样的小数,DIV 才取整数;PostgreSQL 里整数相除直接截断成 2,必须先把某一侧转成 numeric 才能得到小数。比率与百分比计算最容易在这里出错。
基本信息
| MySQL / | 返回 decimal,能得到小数结果 |
|---|---|
| MySQL DIV | 整数除法,直接丢弃小数部分 |
| MySQL % | 取余数,MOD(a, b) 等价 |
| PostgreSQL / | int 除 int 结果仍是 int,直接截断 |
| PostgreSQL 取整 | div(a, b) 等价于整数除法 |
| PostgreSQL 小数 | 先转 numeric 或乘 1.0 再做除法 |
MySQL 除法
MySQL 除法
SELECT 5 / 2; -- 2.5000:返回 decimal,不是整数
SELECT 5 DIV 2; -- 2:整数除法
SELECT 5 % 2; -- 1:取余
SELECT TRUNCATE(5 / 2, 0); -- 2:显式截断,语义比 DIV 更清楚
-- 百分比:先乘 100 再除,避免中途截断
SELECT ROUND(100 * paid / total, 2) AS paid_pct FROM daily_stat;PostgreSQL 除法
PostgreSQL 除法
SELECT 5 / 2; -- 2:整数除法直接截断
SELECT 5.0 / 2; -- 2.5000000000000000
SELECT div(5, 2); -- 2
SELECT (5::numeric / 2); -- 2.5
-- 典型错误:先整数相除再乘 100,结果被截断成 0
SELECT (paid / total) * 100 FROM daily_stat;
-- 正确写法:把小数提前引入
SELECT ROUND(100.0 * paid / total, 2) FROM daily_stat;两库对照
| 表达式 | MySQL 8 | PostgreSQL |
|---|---|---|
| 5 / 2 | 2.5000 | 2 |
| 5 DIV 2 | 2 | 不支持,用 div(5,2) |
| 5 % 2 | 1 | 1(或 mod(5,2)) |
| 5.0 / 2 | 2.5000 | 2.5000000000000000 |
| (5 / 2) * 100 | 250.0000 | 200:先截断再乘 |
| 写比率的安全写法 | 100 * a / b | 100.0 * a / b |
| 取余 | a % b 或 MOD(a,b) | mod(a,b) |
典型使用场景
- 计算占比、转化率、增长率
- 分页:算总页数时需要向上取整配合除法
- 按比例分摊金额,注意最后一位的舍入差
- 统计人均值:总金额除以人数
- 分片路由:取模运算确定落到哪个分片
- 跨库脚本迁移:逐处检查除法的结果类型
- 按比例分摊:多个分项相加要能与总额对上,尾差单独处理
- 平均值计算:先算总和再除行数,分母为 0 时用 NULLIF 兜底
PostgreSQL 里要得到小数结果,至少要有一个操作数是 numeric:写成 100.0 * a / b 或 a::numeric / b。只对最终结果做 CAST 是没用的,截断在除法那一刻就已经发生了。
除法分母为 0 时两库行为不同:MySQL 返回 NULL 并产生告警,PostgreSQL 直接报 division by zero。跨库 SQL 统一用 NULLIF(b, 0) 包住分母,行为才一致。
MySQL 的 DIV 与 / 在代码里极易看错:/ 得到小数、DIV 得到整数。评审涉及金额与比率的 SQL 时,先把运算符两侧的类型和结果类型写进注释。
整数除法先截断会放大误差:小额场景下 (a / b) * 100 可能整列都是 0,报表看上去像没有数据,实际是计算顺序导致的失真。