必须用IS NULL判断NULL,因NULL是未知标记而非值,=NULL恒返回UNKNOWN,WHERE只保留TRUE行;COALESCE比方言函数更兼容,索引对IS NULL支持因数据库而异。

因为 NULL 不是值,而是“未知”的标记,= 运算符在 SQL 中根本无法和它产生 TRUE 或 FALSE 的结果。
WHERE column = 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 这个写法,而是理解 NULL 在整个 SQL 计算链路里的传染性——它能让 =、IN、JOIN、CASE 全部“失真”。一旦涉及空值,每个操作都要单独验逻辑,不能靠直觉推断。

















