= NULL 查不到数据是因为SQL三值逻辑中NULL比较返回UNKNOWN,WHERE只保留TRUE结果;正确写法是IS NULL,它专用于判断缺失状态,非函数且不可加括号。

WHERE column = NULL 为什么查不到任何数据
因为 = NULL 永远不返回 TRUE,它返回的是三值逻辑中的 UNKNOWN。而 WHERE 子句只保留计算结果为 TRUE 的行,UNKNOWN 和 FALSE 都被过滤掉。
哪怕表里有 1000 条 email 是 NULL 的记录,执行 SELECT * FROM users WHERE email = NULL 也一定返回空结果集——这不是数据库 bug,是 SQL 标准强制行为。
-
!= NULL、<> NULL、email = 'NULL'(字符串)全都不对,最后一个甚至会去匹配字面量为'NULL'的记录 - 所有主流数据库(MySQL、PostgreSQL、SQL Server、Oracle)都严格遵循这一规则
- 别指望加个括号或换写法能绕过:例如
WHERE = NULL语法错误,WHERE IS NULL(email)是误当函数调用,直接报错
IS NULL 是谓词,不是函数也不是语法糖
IS NULL 和 IS NOT NULL 是 SQL 标准定义的**谓词(predicate)**,语义就是“判断缺失状态是否存在”,不参与值比较,也不触发类型转换。
它不像 COUNT() 或 COALESCE() 那样接受参数,所以不能加括号,也不能前面加等号:
- ✅ 正确:
WHERE updated_at IS NULL - ❌ 错误:
WHERE updated_at = IS NULL(多写了=) - ❌ 错误:
WHERE IS NULL(updated_at)(当成函数了) - ❌ 错误:
WHERE email IN (NULL)(整个IN表达式变成UNKNOWN)
LEFT JOIN 后用 IS NULL 找“没关联上的记录”最典型
这是 IS NULL 最不可替代的使用场景。比如查“没下过订单的用户”:
SELECT u.name FROM users u LEFT JOIN orders o ON u.id = o.user_id WHERE o.user_id IS NULL;
关键点在于:左连接后,没匹配上的 o.user_id 自动补为 NULL,这时用 IS NULL 就能精准命中;换成 = NULL 则整条 WHERE 失效,结果为空。
- 如果
orders.user_id字段本身定义为NOT NULL,那IS NULL就永远不成立——得先确认表结构是否允许存NULL - 大表上高频执行这类查询时,给
orders.user_id建索引能显著提升性能,尤其在 PostgreSQL 中 B-tree 索引默认包含NULL
IS NULL 和空字符串 '' 完全是两回事
很多人混淆 NULL 和 '',但它们语义完全不同:NULL 是“无值”,'' 是“有值,值为空字符串”。判断方式也必须区分:
-
col IS NULL→ 判断是否缺失 -
col = ''→ 判断是否为空字符串 -
COALESCE(col, '') = ''→ 把NULL转成''后再比,适合统一兜底场景 -
NULLIF(col, '')→ 把空字符串转成NULL,常用于清洗阶段归一化
真正容易被忽略的,是业务逻辑里那些隐性依赖:比如你写了 WHERE status != 'done',却忘了它会漏掉所有 status IS NULL 的记录——因为 NULL != 'done' 仍是 UNKNOWN。

















