SQL聚合函数忽略NULL是明确设计,因NULL代表未知值;AVG/SUM/MAX等仅对已知值计算,全NULL时返回NULL;COUNT(*)统计所有行,COUNT(col)仅统计非NULL值;SUM(COALESCE(col,0))与COALESCE(SUM(col),0)语义相反,不可混淆。

SQL聚合函数忽略NULL不是疏漏,是明确的设计选择——因为NULL代表“未知”,不是0、空字符串或false,强行参与运算会污染统计结果。
AVG()、SUM()、MAX()这些函数为什么跳过NULL
它们只对已知值做计算。比如AVG(salary)遇到NULL,数据库不会猜测这是0元还是100万元,直接跳过;整组全为NULL时,SUM()和AVG()都返回NULL,而不是0。
-
COUNT(*)是唯一不忽略NULL的聚合函数,它统计所有行 -
COUNT(col)只统计col IS NOT NULL的行,差值就是该列NULL数量 -
MAX()和MIN()在全NULL时也返回NULL,下游代码调用getInt()可能直接抛异常
SUM(COALESCE(col, 0)) 和 COALESCE(SUM(col), 0) 区别极大
这两个写法语义完全相反,换错会导致业务逻辑错误:
-
SUM(COALESCE(sales, 0)):每行先补0,再加总。适合“没填金额就当0处理”的场景,如订单汇总 -
COALESCE(SUM(sales), 0):先加总,发现结果为NULL(比如某部门没人填sales)再兜底为0。适合分组报表中“空组显示0”的需求 - 更危险的是表达式:
SUM(total - discount)中任一字段为NULL,整行结果变NULL,必须写成SUM(COALESCE(total, 0) - COALESCE(discount, 0))
LEFT JOIN后聚合字段为NULL,必须提前用COALESCE清洗
JOIN未匹配到右表数据时,字段天然为NULL。这时直接SUM(right_table.amount)会漏掉这些行——不是数据丢了,是被跳过了。
- 典型例子:订单主表
LEFT JOIN优惠券表,coupon_discount为NULL表示没用券,业务上应计为0 - ✅ 正确:
SUM(COALESCE(coupon_discount, 0)) - ❌ 错误:
COALESCE(SUM(coupon_discount), 0)——没用券的订单仍被忽略,总和偏低 - 同理,
AVG(COALESCE(salary, 0))会把[NULL, 10000]算成5000,但真实情况可能是两人均未发薪,不该拉低平均值
WHERE子句里慎用COALESCE或IFNULL
这些函数在SELECT里轻量,但进WHERE通常导致索引失效:
- ❌
WHERE COALESCE(phone, '') = '138xxx'→ 全表扫描 - ✅ 正确写法是分开查,或建函数索引;筛选NULL本身要用
IS NULL - 尤其注意:
WHERE col = ? OR col IS NULL这种条件,数据库很难优化,容易拖慢大表查询
真正容易被忽略的是NULL混杂多重语义的场景:比如一个status字段,NULL可能代表“未提交”“已删除”“系统异常”,盲目用COALESCE(status, 'unknown')会掩盖问题根源。先厘清NULL的业务含义,再决定是否填充、如何填充。

















