因为NULL不是值而是“未知”标记,= NULL恒返回UNKNOWN,而WHERE只保留TRUE行;正确写法是WHERE col IS NULL。

因为 NULL 不是值,而是“未知”的标记,= NULL 永远返回 UNKNOWN,而 WHERE 只保留 TRUE 行。
WHERE col = NULL 为什么查不到数据
SQL 使用三值逻辑(TRUE/FALSE/UNKNOWN),= 是值比较运算符,但 NULL 不代表任何具体值——它表示“缺失”或“未知”。所以 email = NULL 不是在判断“邮箱为空”,而是在问“邮箱是否等于某个未知的东西”,结果恒为 UNKNOWN。WHERE 子句会丢弃所有 UNKNOWN 和 FALSE 行,只留 TRUE。
常见错误现象:
-
SELECT * FROM users WHERE email = NULL返回空结果集,哪怕email列全为NULL -
WHERE age != NULL、WHERE name ''(当name为NULL时)同样无效 -
WHERE status = 'NULL'是在匹配字符串'NULL',不是判空
IS NULL 是唯一标准写法,不是语法糖
IS NULL 和 IS NOT NULL 是 SQL 标准定义的谓词(predicate),语义明确:它不参与值比较,只做存在性判断。它跨数据库兼容(MySQL、PostgreSQL、SQL Server、Oracle 全部支持),且不触发隐式类型转换。
实操要点:
- 查缺失值:
WHERE shipped_at IS NULL - 查非空值:
WHERE backup_name IS NOT NULL——注意这不等价于!= ''或> 0,因为空字符串和数字零都不是NULL - 建表时若写了
NOT NULL DEFAULT '',那该列根本存不了NULL,IS NULL永远查不到数据
IS NULL 能不能走索引?看引擎,别默认能或不能
索引行为取决于数据库实现和索引类型,不能一概而论:
- PostgreSQL 的 B-tree 索引默认包含
NULL,IS NULL通常能高效走索引 - MySQL InnoDB 的 B+Tree 索引默认存储
NULL,但如果在联合索引中IS NULL字段不是最左前缀,或前面有范围查询(如WHERE a > 10 AND b IS NULL),可能无法利用b部分 - 执行前务必用
EXPLAIN确认:看是否有Index Scan或Index Only Scan;没有就考虑加覆盖索引或改写查询
NULL 陷阱不止在 WHERE,聚合和连接里更隐蔽
就算你记住了 IS NULL,其他地方照样容易翻车:
-
COUNT(col)自动跳过NULL行,COUNT(*)统计所有行 —— 两者完全不等价 -
WHERE a.id = b.a_id AND b.status IS NULL在LEFT JOIN中,可能意外过滤掉b全为NULL的关联行,因为a.id = b.a_id在b.a_id为NULL时结果是UNKNOWN -
COALESCE(int_col, 'N/A')在 PostgreSQL 这类强类型库中会报错,必须写成COALESCE(int_col, 0)或COALESCE(int_col::text, 'N/A')
真正麻烦的不是记不住 IS NULL,而是查不出数据时,第一反应是“数据有问题”,却忘了先查表定义和默认约束。

















