sql聚合函数忽略null是三值逻辑的必然结果;avg/sum/max在全null或无匹配时返回null,需coalesce(col,0)预处理而非后兜底;count(*)统计所有行,count(列)仅非null行;left join后聚合须先coalesce再sum;where中用coalesce将致索引失效。

SQL聚合函数忽略NULL不是疏漏,是严格按三值逻辑设计的必然结果;错误不来自函数本身,而来自开发者对NULL语义的误读和兜底时机错配。
AVG()和SUM()返回NULL时程序直接报错
当整组数据全为NULL或WHERE无匹配行时,AVG()、SUM()、MAX()都返回NULL,而非数值0。JDBC用getInt()或MyBatis映射到int类型会抛NullPointerException或类型转换异常。
- 必须在外层用
COALESCE(SUM(col), 0)或IFNULL(SUM(col), 0)(MySQL)兜底 -
COALESCE(AVG(col), 0)只解决空结果问题,但无法修正因部分NULL导致的平均值偏高(比如10人中2人NULL,AVG只算8人) - 若业务要求“缺数据即0”,应在聚合前用
COALESCE(col, 0),而非聚合后补0
COUNT(*)和COUNT(列名)统计结果差得离谱
执行COUNT(status)却以为在统计总订单数,结果比实际少了一半——因为status字段有大量NULL,而COUNT(列名)天然跳过它们。
-
COUNT(*):统计所有行,含全列为NULL的行 -
COUNT(列名):只统计该列非NULL的行数 - 查NULL数量?直接用
COUNT(*) - COUNT(列名) - 想确认某字段是否真为空,别只看
COUNT(列名) = 0,要加WHERE 列名 IS NULL验证
LEFT JOIN后直接SUM右表字段,结果凭空缩水
订单主表LEFT JOIN优惠券表后,SUM(coupon_discount)比实际总优惠金额小——因为没用券的订单,coupon_discount为NULL,被SUM直接跳过。
- ✅ 正确:先清洗再聚合 →
SUM(COALESCE(coupon_discount, 0)) - ❌ 错误:后兜底 →
COALESCE(SUM(coupon_discount), 0),仍漏掉未匹配行 - 涉及多字段运算(如
total - discount),NULL会污染整条表达式,必须每列单独COALESCE:SUM(COALESCE(total, 0) - COALESCE(discount, 0))
WHERE里用COALESCE(phone, '') = '138xxx',查询慢到超时
COALESCE、IFNULL放进WHERE子句,几乎必然导致全表扫描——数据库无法利用phone字段上的索引。
- 筛选NULL请用
WHERE phone IS NULL,别写WHERE COALESCE(phone, '') = '' - 想同时查
NULL和指定值?拆成WHERE phone = '138xxx' OR phone IS NULL,或建函数索引(MySQL 8.0+支持) -
ORDER BY COALESCE(created_at, '1970-01-01')也会使索引失效,优先考虑补数据或改查询逻辑
真正容易被忽略的点在于:NULL不是“空”,也不是“零”,它是“未知”。强行用COALESCE抹平,可能掩盖数据采集缺陷或业务规则漏洞——先确认NULL代表什么,再决定是清洗、过滤,还是保留原语义。











