为什么不能用 == 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 '<col>' cannot be generated always as '<expr>' that would cause a NULL value</expr>使用
JSON_EXTRACT从 JSON 字段取值,缺失路径返回
NULL,此时仍需用
IS NULL判断,不能用
= 'null'—— 后者是在比字符串
真正麻烦的从来不是怎么写
IS NULL,而是忘记它只解决“是否为空”这一步;后续的业务逻辑、索引策略、排序需求,都得跟着重新评估一遍。
