聚合结果比预期小是因为null被静默跳过,必须用coalesce等函数主动兜底;where中= null永远不匹配,须用is null;sum/avg/count(column)默认忽略null,需coalesce转换后计算;变量累加和视图计算也须逐字段兜底,否则静默失效。

聚合结果比预期小,不是数据少了,而是NULL被静默跳过了——必须主动兜底,不能依赖默认行为。
WHERE里用= NULL永远查不到数据
这是最基础也最容易翻车的点:NULL不是值,是“未知”,所以所有常规比较都返回UNKNOWN,等效于FALSE。
- 错误写法:
WHERE status = NULL→ 永远返回空集 - 正确写法:
WHERE status IS NULL或WHERE status IS NOT NULL - 如果业务上想把NULL当作某个具体值(比如
'pending')参与筛选,得先转换:WHERE COALESCE(status, 'pending') = 'pending'
SUM/AVG/COUNT(column)对NULL的“忽略”容易误导
它们不报错,但结果可能违背业务意图。比如“未填=0”时,跳过就等于少算。
-
COUNT(*)统计所有行;COUNT(status)只统计status非NULL的行——两者差值就是NULL数量 -
SUM(amount)跳过NULL,但如果业务要求“缺填即0”,就得写成SUM(COALESCE(amount, 0)) -
AVG(score)分母是“有分人数”,不是“总人数”;若需按“缺考=0分”算平均,得用AVG(COALESCE(score, 0)) - 注意:
COALESCE是标准SQL,ISNULL(SQL Server)和IFNULL(MySQL)是方言,跨库优先选COALESCE
变量累加或计算字段遇到NULL立刻全崩
这不是报错,是静默污染:只要一个NULL进来,整个链式计算就变成NULL,且很难被发现。
-
SET @total = @total + amount;→ 若某次amount为NULL,@total立刻变NULL,后续全失效 - 修复方式不是加
TRY/CATCH,而是提前兜底:SET @total = @total + COALESCE(amount, 0); - 视图里写
price * tax_rate,只要任一为NULL,结果就是NULL;必须在定义层就用COALESCE(price, 0) * COALESCE(tax_rate, 0) - 字符串拼接同理:
CONCAT(first_name, ' ', last_name)遇到任一NULL就返回NULL;应写成CONCAT(COALESCE(first_name, ''), ' ', COALESCE(last_name, ''))
COALESCE放在WHERE或ORDER BY里可能让索引失效
函数包裹列会破坏索引可用性,性能代价隐性但真实。
- 写
WHERE COALESCE(status, 'N') = 'Y'→ 即使status上有索引,也大概率用不上 - 更优解:在业务逻辑或ETL阶段提前把NULL转为确定值落地,查询时直接查
status = 'Y' - 实在要动态处理,可考虑用
CASE WHEN status IS NULL THEN 'N' ELSE status END = 'Y',部分优化器能更好识别
真正麻烦的从来不是写不出COALESCE,而是在复杂JOIN、多层子查询、嵌套视图里漏掉某一处NULL兜底——它不会报错,只会让数字悄悄变小、字段莫名为空、报表连续几周都看不出异样。











