不能用 == NULL 或 = NULL 判断 NULL,因为NULL表示未知值,所有常规比较结果均为UNKNOWN,WHERE只接受TRUE;必须用IS NULL或IS NOT NULL。

为什么不能用 == NULL 或 = NULL 判断 NULL?
因为 SQL 中的 NULL 表示“未知值”,不是某个具体值,所有与 NULL 的常规比较(=、!=、、>= 等)结果都是 UNKNOWN,而 WHERE 子句只接受 TRUE 的行。所以 WHERE col = NULL 永远不匹配任何行,哪怕该列全是 NULL。
正确做法只能用 IS NULL 或 IS NOT NULL —— 它们是专门设计用于判断 NULL 的谓词,返回布尔值 TRUE 或 FALSE。
IS NULL 在 WHERE、JOIN 和函数中的典型用法
它不只是写在 WHERE 里;实际开发中常出现在连接条件、聚合前过滤、以及配合 COALESCE 或 IFNULL 做兜底。
-
WHERE中过滤空值:SELECT * FROM users WHERE email IS NULL;
-
LEFT JOIN后识别“没匹配到”的记录:SELECT u.name, o.order_id FROM users u LEFT JOIN orders o ON u.id = o.user_id WHERE o.user_id IS NULL;
- 和
COALESCE配合提供默认值:SELECT COALESCE(phone, '未填写') AS contact FROM customers;
(注意:这里不用IS NULL,但逻辑上依赖对NULL的识别)
容易踩的坑:NULL 在聚合、索引和 ORDER BY 中的行为
IS NULL 本身没问题,但后续操作如果没意识到 NULL 的特殊性,就会出错。
-
COUNT(col)自动忽略NULL,而COUNT(*)统计所有行 —— 别误以为两者等价 - 普通 B+ 树索引默认不存储全为
NULL的键(除非是唯一索引且允许一个NULL),所以WHERE col IS NULL可能走不了索引,需确认执行计划:EXPLAIN SELECT * FROM logs WHERE status IS NULL;
-
ORDER BY col ASC时,NULL默认排最前;DESC时也排最前(不是最后),如需调整顺序,得显式写ORDER BY col IS NULL, col ASC
MySQL 8.0+ 对 NULL 的增强:隐藏列与生成列中的 NULL 处理
在定义生成列(generated column)或使用不可见列(invisible column)时,表达式若产生 NULL,会直接存入,但约束行为更严格:
- 生成列为
STORED且定义了NOT NULL,但表达式结果为NULL,插入会报错:ERROR 1151 (HY000): Column '' cannot be generated always as ' ' that would cause a NULL value - 使用
JSON_EXTRACT从 JSON 字段取值,缺失路径返回NULL,此时仍需用IS NULL判断,不能用= 'null'—— 后者是在比字符串
真正麻烦的从来不是怎么写 IS NULL,而是忘记它只解决“是否为空”这一步;后续的业务逻辑、索引策略、排序需求,都得跟着重新评估一遍。










