因为null是缺失值标记而非值,= null在sql三值逻辑中恒返回unknown,而where只保留true行,故查不到任何数据;正确写法是where col is null。

WHERE col = NULL 为什么查不到数据
因为 = 是值比较运算符,而 NULL 不是值,它是“缺失值”的标记。SQL 使用三值逻辑(TRUE/FALSE/UNKNOWN),col = NULL 的结果永远是 UNKNOWN;而 WHERE 子句只保留计算结果为 TRUE 的行,UNKNOWN 被当作 FALSE 处理,所以整条查询返回空结果集。
常见错误现象:
-
SELECT * FROM users WHERE email = NULL返回 0 行,哪怕email列全是NULL -
WHERE age != NULL、WHERE name 'NULL'全无效——后者实际在匹配字符串'NULL',不是空值 - Oracle、PostgreSQL、MySQL、SQL Server 全部一致遵循该规则,不是某家数据库的“bug”
正确写法只能是 IS NULL
IS NULL 不是语法糖,是 SQL 标准定义的谓词(predicate),专为判断缺失值设计,语义明确且跨库兼容。
实操建议:
- 查空值:写
WHERE col IS NULL,例如SELECT * FROM orders WHERE shipped_at IS NULL - 查非空值:写
WHERE col IS NOT NULL,注意它不等价于WHERE col != ''或WHERE col > 0—— 空字符串和数字零都不是NULL - 建表时若声明了
email VARCHAR(255) NOT NULL DEFAULT '',那这列根本存不了NULL,email IS NULL永远查不到数据,得查email = ''
两个 NULL 怎么才算“相等”
普通 = 在两边都是 NULL 时仍返回 UNKNOWN,导致 JOIN 或 WHERE a = b 漏掉这些行。必须显式处理空值语义。
通用写法:
-
WHERE (a = b) OR (a IS NULL AND b IS NULL)—— 标准 SQL,所有数据库都支持 - MySQL/MariaDB 可用
WHERE a b(是 NULL 安全等于,NULL NULL返回TRUE) - PostgreSQL 可用
WHERE a IS NOT DISTINCT FROM b,但迁移到其他数据库时需重写
IS NULL 在索引和聚合里容易翻车
就算记住了 IS NULL,在其他上下文里照样出问题:
-
COUNT(col)自动跳过NULL行,COUNT(*)统计所有行——两者完全不等价 -
WHERE col1 = col2在任一列为NULL时整行被过滤,不是“不匹配”,而是“无法判断” -
COALESCE(int_col, 'N/A')在强类型库(如 PostgreSQL)会报错,因为类型不兼容;应写成COALESCE(int_col::TEXT, 'N/A')或统一类型 - 大表上执行
WHERE col IS NULL前,务必看EXPLAIN输出:MySQL 的 B+Tree 索引默认不存NULL,很可能触发全表扫描;PostgreSQL 则通常能走索引
真正麻烦的不是记不住 IS NULL,而是忘了 NULL 在表达式、连接、分组里会把整个逻辑拖进 UNKNOWN 区域——它不等于零,不等于空串,也不等于假,它只是“不知道”。










