<p>SUM(a) / SUM(b)结果为0是因为整数除法截断小数,需用SUM(a) * 1.0 / SUM(b)提升精度并配合NULLIF(SUM(b), 0)防除零,二者缺一不可。</p>

为什么SUM(a) / SUM(b)结果总是0
因为多数数据库(PostgreSQL、SQL Server、旧版MySQL)对整数做除法时直接截断小数,3 / 5得0,不是0.6。哪怕后面套ROUND(..., 2)也救不回来——除法那步已经丢精度了。
-
SUM(a)和SUM(b)返回整型时,整个表达式按整数运算规则执行 - 写成
SUM(a) / SUM(b) * 100也没用:先算3 / 5 = 0,再* 100还是0 - MySQL 8.0+虽会隐式转浮点,但不可靠;PostgreSQL 和 SQL Server 必须显式干预
怎么让除法结果保留小数
核心是让任意一个操作数变成非整型——最轻量、兼容性最好的写法是乘1.0或100.0。
-
SUM(a) * 1.0 / SUM(b):强制提升为浮点,所有主流引擎都认 - 需要百分比就直接用
SUM(a) * 100.0 / SUM(b),别分开乘 - PostgreSQL 可用类型转换语法:
SUM(a)::NUMERIC / SUM(b),更精准适合财务场景 - 避免
CAST(SUM(a) AS DECIMAL(10,2))这类写法——精度声明可能引发隐式截断,尤其在MySQL中
分母为0或NULL怎么办
NULLIF(denominator, 0)是唯一能嵌入任意位置的安全兜底,但它只把0转成NULL,不解决整数截断,也不自动填0。
- 必须组合使用:
SUM(a) * 100.0 / NULLIF(SUM(b), 0) - 如果业务要求分母为0时显示
0而非NULL,再包一层:COALESCE(SUM(a) * 100.0 / NULLIF(SUM(b), 0), 0) - 别用
CASE WHEN SUM(b) = 0 THEN 0 ELSE SUM(a) / SUM(b) END——聚合函数不能出现在CASE判断条件里,语法错或逻辑错 - SQLite 不支持
NULLIF,只能退回到CASE WHEN SUM(b) = 0 THEN NULL ELSE ... END
窗口函数里怎么写才不出错
窗口函数本身不改变数据类型,SUM() OVER()返回的仍是整型,所以同样要加* 1.0或类型转换。
- 错误写法:
COUNT(*) / SUM(COUNT(*)) OVER()→ 全是整数,结果全0 - 正确写法:
COUNT(*) * 100.0 / SUM(COUNT(*)) OVER() - 多层占比(如城市占地区比例)必须用CTE拆解,且每层都要处理类型和除零:
city_sum * 100.0 / NULLIF(SUM(city_sum) OVER (PARTITION BY region), 0) - 别指望
ROUND(..., 2)能修复底层类型问题——它只修显示,不修计算过程
实际写的时候,最容易被忽略的是:类型提升和除零保护必须同时存在,缺一不可。只加NULLIF防不住整数截断,只乘1.0挡不住除零报错。两者像安全带和气囊,得一起用。

















