SQL中的NULL陷阱:为何=永远查不到空值
在 SQL 的三值逻辑里,NULL 表示“未知值”,任何与未知值的比较结果仍然是未知(UNKNOWN),而查询只保留结果为 TRUE 的行,因此 =、<、>、LIKE 等常规运算符“遇 NULL 就消失”,永远得不到 TRUE。
- 三值逻辑(TRUE / FALSE / UNKNOWN)
SQL 的布尔体系不是二值,而是三值:
| 表达式 | 结果 | 说明 |
|---|---|---|
| 5 = 5 | TRUE | 确定相等 |
| 5 = 6 | FALSE | 确定不等 |
| 5 = NULL | UNKNOWN | 不知道 5 与“未知”是否相等 |
| NULL = NULL | UNKNOWN | 两个未知值是否相等?仍是未知 |
| NULL LIKE ‘%x’ | UNKNOWN | 同样未知 |
| NULL > 3 | UNKNOWN | 未知值与 3 的大小关系未知 |
WHERE 子句只保留 TRUE 的行;UNKNOWN 被当作 FALSE 丢弃。
因此
SELECT … WHERE col = NULL
永远返回 0 行,因为没有任何行能使条件为 TRUE。
- 为什么 “=” 不能替代 IS NULL
“=” 是普通比较运算符,遵循上面的三值逻辑。
IS NULL 是 SQL 提供的特殊谓词,它直接检查“是否为缺失值”,返回 TRUE 或 FALSE,不会产生 UNKNOWN。
换句话说:
| 表达式 | 结果 |
|---|---|
| col IS NULL | TRUE 或 FALSE |
| col = NULL | 永远是 UNKNOWN → 被过滤掉 |
因此
WHERE col = NULL -- 语法合法,但逻辑错误
不会报错,也永远查不到数据。
- 为什么 LIKE、>、<、<> 同样失效
它们都是比较类运算符,只要操作符两边出现 NULL,结果就退化为 UNKNOWN,于是行被丢弃。
例子:
-- 假设 tel 里有 NULL 值
WHERE tel LIKE '%5' -- NULL LIKE '%5' → UNKNOWN → 被过滤
WHERE tel > '700' -- NULL > '700' → UNKNOWN → 被过滤
- 唯一正确的做法
- 判断是 NULL:
WHERE col IS NULL - 判断非 NULL:
WHERE col IS NOT NULL
- 小结口诀
“NULL 遇运算符,结果全失踪;
想抓 NULL,只能用 IS,不能用 =。”
