MySQL中NULL参与计算结果静默变为NULL,SUM/AVG/+/CONCAT等均失效;WHERE中column = NULL永远不匹配,须用IS NULL;算术与字符串操作需IFNULL或COALESCE兜底;聚合函数默认忽略NULL,COUNT(column)≠COUNT(*);多列DISTINCT含NULL会漏统计;IFNULL适用于纯MySQL,COALESCE更标准可移植。

MySQL里NULL参与计算,结果不是错,而是“静默变NULL”——你查不到报错,但SUM、AVG、+、CONCAT全会失效,且很难被发现。
WHERE条件里写column = NULL永远查不到数据
这是最常踩的坑:NULL不是值,是“未知”,所以=、!=、>、IN这些比较一律返回UNKNOWN,等效于FALSE。查询直接跳过整行。
- 错误写法:
SELECT * FROM orders WHERE status = NULL→ 返回空集 - 正确写法:
SELECT * FROM orders WHERE status IS NULL - 若想统一处理(比如把NULL当
'pending'),先转换再比较:WHERE IFNULL(status, 'pending') = 'pending'
算术运算和字符串拼接遇到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, '')),不能依赖CONCAT自动跳过
聚合函数(SUM/AVG/COUNT)对NULL的隐式忽略容易误导
SUM和AVG确实跳过NULL,但业务上“未填=0”时,跳过就等于少算;COUNT(column)也只计非NULL行,和COUNT(*)差很多。
-
AVG(score):分母是“有分数的人数”,不是“总人数”。若10人里3人没填,结果按7人算平均 - 要按“缺考=0分”算:
AVG(IFNULL(score, 0)) - 统计“填了姓名的人数”用
COUNT(name);统计“所有记录数”必须用COUNT(*) - 注意
DISTINCT多列时含NULL也会漏统计:COUNT(DISTINCT a, b)会丢掉任意一列为NULL的组合,得用COUNT(DISTINCT IFNULL(a,''), IFNULL(b,''))
IFNULL和COALESCE怎么选?看场景别硬套
两者都能兜底,但行为差异影响结果精度和可移植性:
-
IFNULL(expr1, expr2)是MySQL专属,只支持两个参数,返回类型严格继承expr1(IFNULL(DECIMAL(5,2), 0)仍为DECIMAL(5,2)) -
COALESCE(expr1, expr2, ...)是SQL标准函数,支持多参数,类型按隐式转换规则决定(COALESCE(DECIMAL(5,2), 0)可能升格为DECIMAL(10,2),引发小数位偏差) - 跨库迁移(如将来切PostgreSQL)必须用
COALESCE;纯MySQL项目用IFNULL更稳、更直白 - 性能无实质差别,但别在
WHERE里写WHERE COALESCE(status, '') = 'active'——这会让索引失效
真正难的不是函数怎么写,而是得意识到:NULL不参与比较、不参与运算、不参与排序比较(除非显式声明),它像空气一样存在,却让整个逻辑链悄悄断开。每次写SELECT、UPDATE、GROUP BY前,先问一句——这里有没有字段可能为NULL?它会不会让我的结果“看起来对,其实错”?


















