除 COUNT(*) 外,COUNT(列名)、SUM、AVG、MAX、MIN 均跳过 NULL;SUM(COALESCE(col,0)) 先补零再求和,COALESCE(SUM(col),0) 先求和再兜底;LEFT JOIN 后需用 COALESCE 预处理 NULL;WHERE 中慎用 COALESCE 以防索引失效;NULL 多义性需语义分析,不可盲目填充。

COUNT(*) 是唯一不忽略 NULL 的聚合函数;其余常见聚合函数(COUNT(列名)、SUM、AVG、MAX、MIN)默认跳过 NULL 值——这不是缺陷,是 SQL 标准对“未知值”的保守处理。
哪些聚合函数实际会跳过 NULL?
除 COUNT(*) 外,所有标准单列聚合函数都跳过 NULL:
-
COUNT(列名):只统计该列非NULL的行数 -
SUM(列名):仅对非NULL值求和;整列为NULL时返回NULL,不是0 -
AVG(列名):分母是COUNT(列名),分子是SUM(列名),天然排除NULL -
MAX(列名)和MIN(列名):在非NULL值中比较,全为NULL时返回NULL
SUM(COALESCE(col, 0)) 和 COALESCE(SUM(col), 0) 差在哪?
语义完全不同,选错会导致业务逻辑错误:
-
SUM(COALESCE(sales, 0)):每行先补0,再加总 → 适合“缺记录就当 0 元”场景(如订单汇总) -
COALESCE(SUM(sales), 0):先加总,结果为NULL再兜底 → 适合“空分组显示 0”场景(如某部门无销售记录) - 错误写法:
COALESCE(AVG(sales), 0)只掩盖了空组,但没解决分母变小问题;应改用AVG(COALESCE(sales, 0))(慎用,可能扭曲均值)
LEFT JOIN 后字段为 NULL,聚合前必须预处理
JOIN 未匹配到右表时,字段天然为 NULL。直接聚合会漏掉这些行,不是数据丢了,是被跳过了:
- 典型例子:订单表
LEFT JOIN优惠券表,coupon_discount为NULL表示“没用券”,业务上应计为0 - ✅ 正确:
SUM(COALESCE(coupon_discount, 0)) - ❌ 错误:
COALESCE(SUM(coupon_discount), 0)—— 没用券的订单仍被跳过,总和偏低 - 更隐蔽的问题:
SUM(total - discount)中任一为NULL,整行结果变NULL;得写成SUM(COALESCE(total, 0) - COALESCE(discount, 0))
WHERE 子句里用 COALESCE 会破坏索引
COALESCE 在 SELECT 中轻量,但在 WHERE 里大概率导致全表扫描:
- ❌
WHERE COALESCE(phone, '') = '138xxx'→ 索引失效 - ✅ 查
NULL本身要用IS NULL;想兼顾非空值,优先拆条件或建函数索引 - 注意:
''(空字符串)和NULL完全不同,COUNT(status)会把''计入,但status IS NULL查不到它
最麻烦的从来不是 NULL 是否存在,而是同一列里 NULL 承载多种语义:有的表示“未发生”,有的是“不适用”,有的是“录入失败”。盲目套 COALESCE(col, 0) 会掩盖真实的数据质量问题。

















