主流数据库中int/int为向零截断的整数除法,结果必为int;应使用cast(col as decimal(p,s)) / nullif(cast(den as decimal(p,s)), 0)并合理设置p避免溢出。

因为整数除整数在 SQL Server、MySQL、PostgreSQL 等主流数据库中默认执行整数除法(即截断小数),结果直接舍去所有小数位,返回 INT —— 不是四舍五入,也不是隐式转浮点,就是硬截断。
INT / INT 结果为 0 的真实原因
比如 3 / 5,两个操作数都是 INT,SQL 引擎不经过任何浮点计算,直接按整数除法规则处理:商取整(向零截断),余数丢弃。所以结果是 0,不是 0.6,也不是 0.00。
常见错误现象:
- 写
SUM(completed) / COUNT(*)算完成率,结果全为0或1 - 写
amount / quantity * 100算百分比,结果仍是整数(如25而非25.00) - 用
ROUND(x / y, 2)却发现四舍五入无效——因为x / y这一步已经截断为整数了
CAST/CONVERT 到 DECIMAL 是最可控的解法
相比乘 1.0 或用 1.0/,显式转 DECIMAL(p,s) 能同时解决三件事:避免整数截断、控制精度、防止后续运算溢出或隐式降级。
实操建议:
- 优先用
CAST(col AS DECIMAL(18,4)),而不是col * 1.0—— 后者生成的是FLOAT,可能引入浮点误差(比如0.1 + 0.2 ≠ 0.3) - 除数必须也转
DECIMAL,否则DECIMAL / INT可能触发隐式转换规则,导致精度丢失(SQL Server 中会按操作数精度推导结果类型) - 务必搭配
NULLIF(denominator, 0),否则CAST(100 AS DECIMAL) / 0直接报错,而非返回NULL - 示例:
CAST(num AS DECIMAL(18,4)) / NULLIF(CAST(den AS DECIMAL(18,4)), 0)
ROUND + DECIMAL 组合才能真正“保留两位小数”
ROUND(x, 2) 只是四舍五入到小数点后两位,但返回类型仍可能是 DECIMAL(10,6) 或 FLOAT,显示上可能带多余零(如 25.000000),参与后续计算时还可能被二次隐式转换。
要获得稳定、可导出、可比较的两位小数数值,必须显式定型:
- 错:
ROUND(10.0 / 3, 2)→ 得3.330000(类型未约束) - 对:
CAST(ROUND(10.0 / 3, 2) AS DECIMAL(5,2))→ 得3.33(类型+精度双锁定) - 更稳妥:
CAST(10 AS DECIMAL(5,2)) / CAST(3 AS DECIMAL(5,2))→ 先保精度,再算值,避免 ROUND 中间态
最容易被忽略的一点:DECIMAL 的括号参数 (p,s) 中的 p(总位数)不能只看小数位——如果分子很大(如千万级金额),DECIMAL(5,2) 会直接截断或报错,必须提前估算最大可能值并留足整数位空间。











