在MySQL中,NULL表示未知或缺失的值,它不参与常规的大小比较,也不能用等号去判断。当我们需要从一张表中找出两个或两个以上字段为NULL的记录时,如果仍然沿用等号思维就会查不到任何数据。本文围绕这一实际需求,介绍几种在MySQL中稳定、高效地求解多字段NULL记录的方法。

为什么不能用等号查询NULL
很多刚接触MySQL的开发者会直觉地写出类似 WHERE col1 = NULL AND col2 = NULL 的语句,但这是错误写法。在SQL标准里,任何与NULL进行的算术或比较运算结果都是NULL,而WHERE条件只保留结果为真(TRUE)的行,因此这类写法永远返回空集。正确的判断方式是使用 IS NULL 运算符。
此外,NULL与空字符串不同。空字符串是一个长度为0的有效值,可以用等号比较;而NULL意味着该列值未被填入。在表结构设计时,如果某些字段允许为空,那么在数据质量分析时,统计这些字段的缺失情况就成为常见任务。理解NULL的语义,是写出正确查询语句的前提。
使用IS NULL配合OR条件
最直接的方法是把每一个可能为NULL的字段都用IS NULL判断,然后通过OR把“任意两个为空”的组合列出来。假设有一张用户联系表 user_contact,包含 phone、email、wechat 三个字段,我们要找出其中至少两个为NULL的记录。
三个字段中任选两个为NULL,一共有三种组合,加上三个全为NULL的情况,可以用下面的SQL表达:
SELECT * FROM user_contact WHERE (phone IS NULL AND email IS NULL) OR (phone IS NULL AND wechat IS NULL) OR (email IS NULL AND wechat IS NULL);
这种写法的优点是非常直观,数据库优化器也容易理解。如果相关字段上建立了索引,部分条件有可能用到索引合并。缺点是当字段数量变多时,组合条件会呈平方级增长,SQL会变得冗长且难以维护。
利用CASE WHEN与SUM统计NULL个数
更通用的思路是:在SELECT或WHERE中,把每个字段是否为NULL转成0或1,然后求和,判断总和是否大于等于2。MySQL中可以用 CASE WHEN col IS NULL THEN 1 ELSE 0 END 实现,也可以利用 IS NULL 返回布尔值再转数字的小技巧。
下面示例用一个表达式统计NULL字段数量,并筛选数量不小于2的行:
SELECT *
FROM user_contact
WHERE (CASE WHEN phone IS NULL THEN 1 ELSE 0 END
+ CASE WHEN email IS NULL THEN 1 ELSE 0 END
+ CASE WHEN wechat IS NULL THEN 1 ELSE 0 END) >= 2;
这种写法扩展性很好,无论有多少字段,只需要继续累加CASE表达式即可,不用列举组合。在性能上,它会对每行做表达式计算,通常无法直接使用单列索引,但在全表扫描场景下比大量OR条件更易于阅读和优化器处理。如果表很大,可以考虑先通过单列索引过滤掉明显不可能满足条件的行,再做表达式计算。
使用存储过程或生成列简化查询
如果这类统计是高频需求,可以在表中增加一个生成列(generated column),提前把NULL个数算好并建索引。例如:
ALTER TABLE user_contact
ADD COLUMN null_count INT AS (
(CASE WHEN phone IS NULL THEN 1 ELSE 0 END)
+ (CASE WHEN email IS NULL THEN 1 ELSE 0 END)
+ (CASE WHEN wechat IS NULL THEN 1 ELSE 0 END)
) STORED,
ADD INDEX idx_null_count (null_count);
SELECT *
FROM user_contact
WHERE null_count >= 2;
生成列在插入或更新时由MySQL自动维护,查询时直接走索引,适合数据量大且查询频繁的系统。需要注意的是,生成列的定义必须基于确定性的表达式,上述CASE写法满足要求。对于历史表不便修改结构的场景,也可以把统计逻辑封装成视图,对外提供统一查询接口。
总结与避坑建议
查询两个或以上字段为NULL的记录,核心是放弃等号、改用IS NULL,并通过逻辑组合或计数方式表达“至少两个”的语义。简单场景用OR组合即可;字段多或需求通用时,用CASE WHEN求和更清晰;高频查询则可用生成列加索引提升性能。
实际写SQL时,还应留意字段默认值。如果业务上用空字符串代替NULL,那么判断逻辑要改成 col = '' OR col IS NULL,否则会漏掉空字符串的记录。另外在GROUP BY或COUNT统计中,COUNT(col)会忽略NULL,而COUNT(*)不会,这也是分析缺失数据时常踩的坑。