AVG()自动忽略NULL是ANSI SQL标准行为,分母为COUNT(col)而非COUNT(),导致“全体平均”与“有效值平均”语义不同;需显式检查COUNT()与COUNT(col)差异并按业务含义处理NULL。

AVG() 自动忽略 NULL 是标准行为,不是 bug;偏差根源在于你没意识到它悄悄改了分母——你以为除以总行数,实际除以非 NULL 行数。
AVG(col) 的分母永远是 COUNT(col),不是 COUNT(*)
这是 ANSI SQL-92 第 10.9 条强制规定:NULL 表示“未知”,不能参与确定性算术。所以 AVG(score) 等价于 SUM(score) / COUNT(score),而不是 SUM(score) / COUNT(*)。
- 数据为
[10, NULL, 20, 0]时:AVG(score)= (10 + 20 + 0) / 3 = 10,COUNT(score)= 3,COUNT(*)= 4 - 业务上想算“全体用户平均付费”,但
AVG(amount)实际算的是“已付费用户的平均金额”——差了一个量级 - 传感器表中
temperature IS NULL表示“设备离线”,填 0 后均值会被系统性拉低,而AVG()还在默默用更小的分母算
COALESCE(AVG(col), 0) 和 AVG(COALESCE(col, 0)) 完全不是一回事
前者只兜底整组为 NULL 的情况(比如某用户从未打分),后者把每个 NULL 强制转成 0 再参与计算——分母变大、分子被污染,语义彻底扭曲。
-
COALESCE(AVG(score), 0):某用户无评分 → 返回 0,不改变原始计算逻辑 -
AVG(COALESCE(score, 0)):把“未打分”当成“打了 0 分”,均值虚低;订单表amount为 NULL 表示“未下单”,却按 0 算 → LTV 模型失真 - 真正要按总人数摊薄,得写
SUM(COALESCE(amount, 0)) / COUNT(*),不是套一层AVG()
光看 AVG() 结果永远不知道分母是多少
AVG() 不报错、不警告、也不告诉你它除以几。同一列,COUNT(*)、COUNT(col)、COUNT(NULLIF(col, 0)) 可能完全不同,而你只盯着那个平均数。
- 必须显式查:
SELECT AVG(x), COUNT(*), COUNT(x), COUNT(NULLIF(x, 0)) FROM t - 如果
COUNT(x)远小于COUNT(*),说明缺失严重,不能直接拿平均值做决策 - 在子查询或视图里嵌套
AVG(),外部再加WHERE,分母已经不是原始表的COUNT(*),也不是你直觉里的“这组该有多少人”
最常被忽略的,不是 NULL 本身,而是同一列里不同 NULL 的业务含义混在一起:有的是“未发生”,有的是“不适用”,有的是“录入失败”。这时候统一 COALESCE(col, 0),等于把三类问题强行压成一个数字,后续谁都看不出哪块出了问题。

















