NULL参与计算结果静默为NULL,WHERE中= NULL不匹配需用IS NULL;聚合函数忽略NULL,COUNT(*)统计全行而COUNT(col)仅非NULL;兜底优先选IFNULL(双参数)或COALESCE(多参数跨库兼容)。

直接结论:NULL参与计算不会报错,但结果静默变为NULL,且WHERE中= NULL永远不匹配——这不是bug,是SQL标准行为,必须主动兜底或改写逻辑。
WHERE中col = NULL查不到数据,得用IS NULL
这是最常踩的坑。MySQL里NULL不是值,是“未知”,所以所有常规比较(=、!=、IN、BETWEEN)对NULL都返回UNKNOWN,等效于FALSE,整行被过滤掉。
- 错误写法:
SELECT * FROM users WHERE email = NULL→ 永远返回空集 - 正确写法:
SELECT * FROM users WHERE email IS NULL - 若业务上想把
NULL当作'unknown'统一处理,先转换再比:WHERE IFNULL(email, 'unknown') = 'unknown'
SUM/AVG/+/CONCAT遇到NULL就中断
算术和字符串操作有“传染性”:只要任一操作数为NULL,结果就是NULL。这在变量累加、拼接、聚合中极易引发静默偏差。
-
5 + NULL→NULL;CONCAT('A', NULL)→NULL - 变量累加崩溃:
SET @sum = @sum + amount→ 一旦amount为NULL,@sum立刻变NULL,后续全失效 - 修复方式必须显式兜底:
SET @sum = @sum + IFNULL(amount, 0) - 字符串拼接别依赖自动跳过:
CONCAT(IFNULL(first_name, ''), ' ', IFNULL(last_name, ''))
COUNT(column)和COUNT(*)统计口径完全不同
聚合函数默认忽略NULL,但业务含义常与直觉相反。比如AVG(score)分母是“有分数的人数”,不是“总人数”;COUNT(name)漏掉所有name IS NULL的记录。
- 统计“所有记录数”必须用:
COUNT(*) - 统计“填了姓名的人数”用:
COUNT(name) - 按“缺考=0分”算平均:
AVG(IFNULL(score, 0)) -
COUNT(DISTINCT a, b)会丢掉任意一列为NULL的组合,需写成:COUNT(DISTINCT IFNULL(a, ''), IFNULL(b, ''))
选IFNULL还是COALESCE?看参数个数和兼容性
两者都能兜底,但语义和行为差异影响结果精度和迁移成本。
-
IFNULL(expr1, expr2)只支持两个参数,类型严格继承expr1,MySQL专属,性能略高 -
COALESCE(expr1, expr2, ...)是SQL标准,支持多参数链式fallback,但所有参数会隐式转为最高优先级类型(如COALESCE(DECIMAL(5,2), 0)可能升格为DECIMAL(10,2)) - 仅需填0或固定字符串:
IFNULL(price, 0)更直白 - 需多级fallback(如
email_work→email_personal→'no-email'):COALESCE(email_work, email_personal, 'no-email')是唯一选择 - 跨库迁移(如将来切PostgreSQL)必须用
COALESCE
真正难的不是写IFNULL,而是判断哪里该兜、兜成什么——比如“未填电话”该补''还是'未提供',这取决于下游系统是否把空字符串当有效值。这类业务语义,数据库层没法替你决定。


















