聚合场景下直接写sum(a)/sum(b)必报错,因某组sum(b)=0时数据库执行除法即崩溃;正确写法是sum(a)/nullif(sum(b),0),并配合100.0和coalesce确保浮点结果与兜底值。

聚合场景下直接写 SUM(a)/SUM(b) 必报错
只要某组的 SUM(b) 结果为 0,查询就会中断并抛出 division by zero(PostgreSQL/SQL Server)或类似错误。这不是数据缺失,是执行时语法级崩溃——连 NULL 都不返回。原因在于:聚合函数输出的是标量值,数据库不会提前判断分母是否为 0,而是直接计算除法表达式。
NULLIF 必须用在分母位置,且只作用于聚合后结果
NULLIF 是唯一能安全嵌入任意聚合表达式的防除零方案。它只在两个参数相等时返回 NULL,否则返回第一个参数值。关键点:
-
NULLIF(SUM(b), 0)有效:对已算出的标量值做判断 -
NULLIF(b, 0)在GROUP BY中无效:这是逐行处理,无法解决聚合后分母为 0 的问题 -
SUM(a) / NULLIF(SUM(b), 0)✅ 正确;NULLIF(SUM(a), 0) / SUM(b)❌ 无意义 - 所有主流数据库(PostgreSQL、SQL Server、MySQL 8.0+、SQLite)都支持该用法,但 SQLite 要求传入单值(即必须在聚合之后)
别漏掉浮点转换和最终兜底
即使加了 NULLIF,整数除法仍会截断。例如 SUM(done)=3、SUM(plan)=5,3 / NULLIF(5, 0) 在整型上下文中结果是 0,不是 0.6。同时,NULLIF 返回 NULL 后,业务常需显示 0 或 'N/A',而非空值。
- 强制浮点:用
100.0而非100,如SUM(done) * 100.0 / NULLIF(SUM(plan), 0) - 最终兜底:用
COALESCE包裹整个表达式,COALESCE(SUM(done) * 100.0 / NULLIF(SUM(plan), 0), 0.0) - 切忌错误写法:
SUM(done) * 100.0 / COALESCE(NULLIF(SUM(plan), 0), 0)—— 这会让分母变成 0,重新触发除零
CASE WHEN 在聚合中基本不可用
有人试图写 CASE WHEN SUM(b) = 0 THEN 0 ELSE SUM(a)/SUM(b) END,但绝大多数数据库(包括 MySQL 5.7、PostgreSQL、SQL Server)**禁止在 CASE 的 WHEN 子句中直接使用聚合函数**,会报语法错误。即使某些版本允许,逻辑也容易被优化器重排或受隐式类型转换干扰(尤其旧版 MySQL)。它只适合单行计算场景,比如 CASE WHEN views = 0 THEN NULL ELSE sales/views END。
真正难处理的从来不是“怎么写”,而是忘记浮点转换、把 COALESCE 错包在分母里、或误以为 CASE 能通吃所有场景——这些细节一错,结果就静默失真,比报错更危险。











