WHERE column = NULL查不到数据,因为NULL是“未知”标记而非值,=比较恒返回UNKNOWN,而WHERE只保留TRUE结果;正确写法是WHERE column IS NULL。

因为 = NULL 永远不返回 TRUE,WHERE 只保留 TRUE 行,所以查不到任何数据。
WHERE column = NULL 为什么查不到数据
NULL 不是值,而是“未知”的标记。SQL 使用三值逻辑(TRUE / FALSE / UNKNOWN),而 = NULL 的结果恒为 UNKNOWN。WHERE 子句只保留计算结果为 TRUE 的行,UNKNOWN 被直接丢弃。
- 常见错误现象:
SELECT * FROM users WHERE email = NULL返回空结果集,哪怕表里有几百条email是NULL的记录 -
!= NULL、NULL、email = 'NULL'全都不对——后者实际在匹配字面量为'NULL'的字符串 - Oracle、PostgreSQL、MySQL、SQL Server 全部遵循这一规则,不是某家数据库的“bug”
IS NULL 是谓词,不是语法糖
IS NULL 和 IS NOT NULL 是 SQL 标准定义的**专门谓词(predicate)**,语义明确:不参与比较运算,只做存在性判断。
- 它不触发类型转换,也不依赖隐式规则,跨数据库行为一致
- 建表时若声明
email VARCHAR(255) NULL,才表示该字段允许存缺失值;但若写成NOT NULL DEFAULT '',那用email IS NULL永远查不到——得查email = '' - 某些方言(如 PostgreSQL)支持
col1 IS NOT DISTINCT FROM col2做空值安全比较,但IS NULL才是通用解法
IS NULL 在索引和性能上的实际表现
能不能走索引,取决于数据库引擎和索引类型,不能一概而论。
- MySQL 的普通 B+Tree 索引默认不存储
NULL值,所以WHERE status IS NULL很可能触发全表扫描(除非你建了函数索引,比如INDEX (status)配合WHERE status NULL,但这是 MySQL 特有,非标) - PostgreSQL 的 B-tree 索引默认包含
NULL,IS NULL和IS NOT NULL都能高效使用索引 - 大表上执行
WHERE col IS NULL前,先看执行计划:EXPLAIN输出里有没有Index Scan或Index Only Scan;没有的话,考虑加覆盖索引或改用物化视图预计算
空值陷阱不止在 WHERE 里
即使你记住了 WHERE col 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(price, 0)看似安全,但如果price是DECIMAL类型,而0被解释为整数,某些强类型数据库(如 PostgreSQL)会报错,得写成COALESCE(price, 0.0)
真正麻烦的不是记不住 IS NULL,而是忘了它只解决“是否存在”,不解决“怎么处理”。后续要用 COALESCE、NULLIF 或应用层可空类型来承接,否则空值会在聚合、连接、排序中反复冒头。

















