NULLIF(分母, 0)是唯一轻量且跨库兼容的防除零方案,它将分母为0转为NULL,利用“任何数÷NULL= NULL”避免报错;必须置于分母位置,如SUM(revenue)/NULLIF(SUM(cost),0),放错则失效。

直接用 NULLIF(分母, 0) 包住分母,是唯一既轻量又跨库兼容的防除零方案;它不阻止计算,而是让分母在为 0 时变成 NULL,从而触发 SQL 标准中“任何数 ÷ NULL = NULL”的语义,避免中断查询。
为什么必须把 NULLIF 放在分母位置
NULLIF 的作用机制是“相等即转 NULL”,它只改变被包裹表达式的值,不干预运算顺序。一旦放错位置,就完全失效:
- ✅ 正确:
SUM(revenue) / NULLIF(SUM(cost), 0)—— 分母被转NULL,除法安全 - ❌ 错误:
NULLIF(SUM(revenue), 0) / SUM(cost)—— 分母仍是SUM(cost),照样报错 - ❌ 错误:
NULLIF(SUM(revenue) / SUM(cost), 0)—— 除法先执行,错误已抛出
特别注意:NULLIF(0, SUM(cost)) 是常见手误,它永远返回 0 或 NULL,对防除零毫无意义。
聚合后除法必须加 NULLIF,不能靠 HAVING 过滤
有人想用 HAVING SUM(cost) > 0 排除分母为 0 的组,但这会直接丢掉整组数据——而业务上往往需要保留“0 成本、0 收入”这类有效空组,仅让指标显示为 NULL 或占位符。
-
GROUP BY dept下,SUM(sales) / NULLIF(COUNT(*), 0)能正确计算每个部门人均值,包括全员无订单的部门(结果为NULL) - 若用
HAVING COUNT(*) > 0,这些部门将从结果集中彻底消失 -
WHERE更不行:聚合字段不能出现在WHERE子句中
防住报错只是第一步,NULL 结果必须按业务解释
NULLIF 只解决“不断查询”,不解决“怎么呈现”。前端或 BI 工具遇到 NULL 可能渲染为空白、报类型错误,甚至被 AVG() 忽略导致统计偏差。
- 转化率要求“分母为 0 时显示 0%”:用
COALESCE(SUM(paid) * 100.0 / NULLIF(SUM(clicks), 0), 0.0) - 需区分“真实 0%”和“无数据”:用
CASE WHEN SUM(clicks) = 0 THEN 'N/A' ELSE CAST(SUM(paid)*100.0/NULLIF(SUM(clicks),0) AS DECIMAL(5,2)) END - 千万避免:
SUM(paid) * 100.0 / COALESCE(NULLIF(SUM(clicks), 0), 0)—— 外层COALESCE把NULL换回0,立刻复现除零
真正容易被跳过的细节:乘 100.0 而非 100,否则整数除法截断(如 3/5 = 0),再乘 100 还是 0。

















