必须用IS NULL判断NULL,因为NULL是未知标记而非值,=NULL恒返回UNKNOWN,而WHERE只保留TRUE行;所有主流数据库均遵循此三值逻辑标准。

WHERE column = NULL 为什么查不到任何数据
因为 = NULL 的比较结果永远是 UNKNOWN,而 WHERE 子句只保留计算结果为 TRUE 的行。UNKNOWN 被直接过滤掉,所以哪怕字段全是 NULL,SELECT * FROM t WHERE col = NULL 也一定返回空结果集。
这不是 MySQL 或 PostgreSQL 的“bug”,而是 SQL 标准规定的三值逻辑(TRUE/FALSE/UNKNOWN)行为,所有主流数据库(Oracle、SQL Server、PostgreSQL、MySQL)都严格遵循。
-
col = NULL、col != NULL、col NULL全部等效,全都不成立 -
col = 'NULL'是在匹配字符串字面量'NULL',不是判空 -
IS NULL不是函数,不能写成IS NULL(col)或= IS NULL
IS NULL 是谓词,不是语法糖
IS NULL 和 IS NOT NULL 是 SQL 标准定义的**谓词(predicate)**,语义就是“检测该值是否处于未知/缺失状态”,不参与常规比较运算,也不触发类型隐式转换。
它和 = 的根本区别在于:前者回答“是否存在”,后者试图回答“是否相等”——而 NULL 没有可比性。
- 跨数据库行为一致:MySQL、PostgreSQL、SQL Server、Oracle 全部支持且语义相同
- 不依赖字段类型:对
INT、VARCHAR、DATE等都适用 - 不能嵌套或组合:比如
WHERE (col IS NULL) = TRUE是非法语法
IS NULL 在索引和 JOIN 中的实际表现
能不能走索引,取决于数据库实现和索引结构,不能默认认为“IS NULL 就慢”或“IS NULL 一定走索引”。
例如:
- PostgreSQL 的 B-tree 索引默认包含
NULL值,WHERE col IS NULL可能触发Index Scan - MySQL 的普通 B+Tree 索引默认不存储
NULL,IS NULL很可能回表或全扫,除非建了函数索引(如INDEX (col)配合WHERE col IS NULL的特定版本) - 在
LEFT JOIN后用WHERE right_table.id IS NULL找“未关联记录”时,若right_table.id字段本身是NOT NULL,那这个条件才真正有意义;如果它允许NULL且有默认值,就得先确认数据来源
别只盯着 WHERE,NULL 在其他地方照样翻车
记住 IS NULL 只解决 WHERE 判空,但聚合、连接、表达式里还有大量隐性陷阱。
-
COUNT(col)自动跳过NULL行,COUNT(*)不跳——两者完全不等价 -
WHERE a.col = b.col在任一列为NULL时整行被丢弃,想安全比较得用a.col IS NOT DISTINCT FROM b.col(PostgreSQL)或手动写(a.col = b.col) OR (a.col IS NULL AND b.col IS NULL) -
COALESCE(col, 'default')是推荐的空值替换方式,但注意类型兼容性:COALESCE(price, 0)在 PostgreSQL 中可能报错,应写成COALESCE(price, 0::DECIMAL)或COALESCE(price, 0.0) - 最常被忽略的一点:查不出数据时,第一反应不该是“SQL 写错了”,而是
DESCRIBE table_name或查information_schema.columns,确认该列是否真的允许NULL——很多字段看着该为空,其实建表时加了NOT NULL DEFAULT ''
实际写 SQL 时,最麻烦的从来不是记不住 IS NULL,而是当查询没结果,下意识怀疑数据或逻辑,却忘了先看表结构里那个小小的 Null 列是不是标着 NO。

















