AVG()自动忽略NULL,无需WHERE过滤;业务上需明确NULL和0的语义:用COALESCE(AVG(col), 0)兜底整组NULL,用AVG(COALESCE(col, 0))将NULL视作0参与计算,用AVG(NULLIF(col, 0))排除0值而不影响行结构。

AVG() 本身已经忽略 NULL,不需要额外处理;真正影响准确性的,是业务上要不要把 NULL 当成“0”、或者该不该排除 0 值。
AVG(column) 默认就跳过 NULL,加 WHERE column IS NOT NULL 是多余的
只要字段类型允许 NULL,AVG(column) 就自动只对非 NULL 值求和并除以非 NULL 行数。比如数据为 [10, 20, NULL, 30],结果是 (10 + 20 + 30) / 3 = 20,不是 /4。加 WHERE column IS NOT NULL 不改变结果,反而可能掩盖后续逻辑问题——比如你同时要统计 COUNT(*) 或关联其他字段时,WHERE 会整行过滤,破坏上下文。
- 冗余写法:
SELECT AVG(salary) FROM employees WHERE salary IS NOT NULL - 推荐写法:
SELECT AVG(salary) FROM employees - 例外:当你需要同步过滤其他无效值(如
salary = -999)时,WHERE 才有意义,且应显式写出AND salary IS NOT NULL保证语义清晰
全 NULL 组返回 NULL,下游报错?用 COALESCE(AVG(col), 0) 补兜底
分组后某组所有值都是 NULL(例如某部门全员未填报绩效),AVG(col) 返回 NULL,不是 0,也不是报错。这会让 BI 工具图表断值、前端渲染失败、或触发空指针异常。
- 错误写法:
COALESCE(AVG(col), 0)只在整组结果为 NULL 时补 0,但没解决原始数据缺失问题 - 正确写法:
AVG(COALESCE(col, 0))—— 先把 NULL 补成 0,再算平均(注意:这会拉低均值,仅适用于“未填报=0”业务场景) - 更安全的兜底:
COALESCE(AVG(col), 0)适合报表层快速防断,不改变原始聚合逻辑
想排除 0 值(而非 NULL)?用 NULLIF(col, 0) 替代 WHERE
当 0 表示“无效采集”(如 API 耗时为 0、传感器读数为 0),而字段本身又允许 NULL,直接 WHERE col != 0 会丢弃整行,影响同组其他聚合(比如你还要算 COUNT(*) 或关联用户 ID)。这时应该让 0 “变成 NULL”,再由 AVG 自动跳过。
- 推荐写法:
AVG(NULLIF(col, 0))——col = 0时返回 NULL,否则返回原值,AVG 自然忽略 - 对比
WHERE col != 0:前者保留行结构,后者破坏分组完整性 - 负值需保留时(如温度变化),必须用
!= 0或NOT IN (0),避免误删负数
验证分母到底有多少?查 COUNT() 才能确认计算基数
光看 AVG() 结果无法判断它基于几条记录算的。同一份数据,COUNT(col)、COUNT(*)、COUNT(NULLIF(col, 0)) 可能完全不同。
- 执行这个语句一眼看清:
SELECT AVG(x), COUNT(x), COUNT(*), COUNT(NULLIF(x, 0)) FROM t -
COUNT(x):参与 AVG 计算的实际行数(非 NULL) -
COUNT(*):总行数(含 NULL 和 0) -
COUNT(NULLIF(x, 0)):非零非 NULL 行数(即你想排除 0 后的真实基数) - 嵌套子查询或视图中用 AVG 时,外部加 WHERE 会悄悄改变分母——务必在最终层级校验这些 COUNT 值
最常被忽略的点:业务语义优先于语法。0 是真实值(如库存)还是占位符(如埋点失败)?NULL 是缺失(如新员工未定薪)还是非法(如评分系统根本不允许空)?不问清楚这点,再准的 SQL 也导不出可信结论。

















