AVG()忽略NULL是SQL标准行为,分母为COUNT(score)而非COUNT(),导致静默缩减排除NULL行;高缺失率时结果失真,COALESCE(score,0)篡改语义,空组返回NULL易引发崩溃,需用COALESCE(AVG(score),0)兜底并配合COUNT(score)和COUNT()校验。

AVG() 忽略 NULL 不是 bug,是 SQL 标准对“未知值”的保守处理——但它会静默改变分母,导致平均值偏离业务真实口径。你看到的数字没错,但它的基数可能不是你想象的那个。
AVG(score) 的分母到底是 COUNT(*) 还是 COUNT(score)?
是 COUNT(score),不是 COUNT(*)。这意味着只要某行 score 为 NULL,它既不参与求和,也不参与计数。比如 10 行数据里有 3 个 NULL,AVG(score) 实际算的是 SUM / 7,而不是 SUM / 10。
- 这个过程完全静默:无警告、不报错、不提示分母缩水
- 当缺失率高(如
COUNT(score) / COUNT(*) ),AVG()结果参考价值极低 - 在
GROUP BY场景下,不同组的分母差异更大,横向对比失真风险陡增
COALESCE(score, 0) 看似补全,实则篡改语义
把 NULL 强制转成 0,等于把“未知”定义为“已知为零”。这在业务上往往不可接受:
- 传感器表中
temperature IS NULL表示设备离线,填0会系统性拉低均值 - 员工表中
salary IS NULL可能代表“未定薪”,填0就等同认定其零收入 -
AVG(COALESCE(score, 0))的分母仍是COUNT(score),不是COUNT(*),所以它 ≠SUM(COALESCE(score, 0)) / COUNT(*)
空结果集或全 NULL 组返回 NULL,应用层极易崩溃
像 SELECT AVG(score) FROM ratings WHERE user_id = 999 这种查询,结果就是 NULL。下游代码若没兜底,会直接出错:
- Java 中
ResultSet.getDouble()抛SQLException - Python 中
row[0]是None,后续参与算术运算触发TypeError - 前端渲染显示为
null字符串或空白,而非“暂无数据” - 正确兜底写法:
COALESCE(AVG(score), 0)(通用)或IFNULL(AVG(score), 0)(MySQL)
GROUP BY + AVG() 时必须并列输出三个指标校验完整性
仅看 AVG(score) 不足以判断该组平均值是否可信。必须同时查:
-
AVG(score):当前组均值 -
COUNT(score):实际参与计算的非空行数 -
COUNT(*):该组总行数
三者对照才能判断缺失比例。例如某组 COUNT(score) = 2 而 COUNT(*) = 10,说明 80% 数据缺失,这个 AVG() 几乎不能代表该组真实水平。










