← 返回题目列表

SQL 中 NULL 和三值逻辑如何影响查询结果?

高频 中等 第 14 / 28 题 更新于 2026/07/29
SQLNULL三值逻辑

简化版

NULL 表示未知或缺失,不能用 = NULL 判断,应该用 IS NULL;SQL 条件逻辑有 TRUE/FALSE/UNKNOWN 三种结果,WHERE 只保留 TRUE

详细版

在 SQL 里,NULL 不是空字符串、不是 0,也不是一个普通值。表达式 col = NULL 的结果不是 TRUEFALSE,而是 UNKNOWN,因此不会被 WHERE 保留下来。

正确判断空值要使用:

WHERE col IS NULL
WHERE col IS NOT NULL

三值逻辑会影响比较、IN/NOT IN、聚合函数、排序和唯一约束等场景。比如 COUNT(col) 不统计 NULLCOUNT(*) 统计行数;NOT IN 子查询中如果含 NULL,结果可能出乎意料。

完整版教学

一、NULL 不是普通值

NULL 更接近“未知、缺失、不可用”。既然未知,就不能说它等于某个值,也不能说它不等于某个值。

SELECT *
FROM users
WHERE phone = NULL;

这条 SQL 通常查不到手机号为空的用户,因为 phone = NULL 的判断结果是 UNKNOWN

正确写法是:

SELECT *
FROM users
WHERE phone IS NULL;

记忆钩子:遇到 NULL,不要问“等不等于”,要问“是不是空值状态”。

二、三值逻辑是什么

普通编程语言里条件常是两值逻辑:truefalse。SQL 引入 NULL 后,比较结果多了一个 UNKNOWN

5 = 5       -> TRUE
5 = 6       -> FALSE
NULL = 5    -> UNKNOWN
NULL = NULL -> UNKNOWN

WHERE 子句只保留结果为 TRUE 的行,FALSEUNKNOWN 都会被过滤掉。

表达式结果是否被 WHERE 保留
age > 18 且 age=20TRUE
age > 18 且 age=16FALSE
age > 18 且 age=NULLUNKNOWN

这就是很多空值数据“莫名消失”的根源。

三、AND/OR 遇到 UNKNOWN 怎么算

三值逻辑不是简单把 UNKNOWNFALSE。它表示不知道,因此和其他条件组合时要按语义推导。

TRUE AND UNKNOWN  -> UNKNOWN
FALSE AND UNKNOWN -> FALSE
TRUE OR UNKNOWN   -> TRUE
FALSE OR UNKNOWN  -> UNKNOWN

例如:

SELECT *
FROM users
WHERE age > 18 AND phone = '13800000000';

如果 age=20phone=NULL,第二个条件是 UNKNOWN,整体是 UNKNOWN,不会返回。

如果条件是 age > 18 OR phone = '13800000000'age=20 已经能让整体为 TRUE,这行会返回。

四、NOT IN 和 NULL 是高频陷阱

NOT IN 的坑非常经典。假设黑名单表里有一个 NULL

-- blacklist.user_id: 2, NULL
SELECT id
FROM users
WHERE id NOT IN (SELECT user_id FROM blacklist);

id=1 来说,判断近似变成:

1 <> 2 AND 1 <> NULL
TRUE AND UNKNOWN -> UNKNOWN

结果不是 TRUE,所以 id=1 也不会返回。很多人以为应该返回“不在黑名单”的用户,结果查出 0 行。

更稳的写法是过滤子查询空值,或使用 NOT EXISTS

SELECT u.id
FROM users u
WHERE NOT EXISTS (
  SELECT 1
  FROM blacklist b
  WHERE b.user_id = u.id
);

五、聚合函数对 NULL 的处理

聚合函数也有明确规则:COUNT(*) 统计行数,COUNT(col) 统计非 NULL 的列值数量。

-- scores: 100, 80, NULL
SELECT
  COUNT(*) AS row_count,
  COUNT(score) AS score_count,
  AVG(score) AS avg_score
FROM exams;

结果是:

row_count | score_count | avg_score
3         | 2           | 90

AVG(score) 只用 100 和 80 计算,不把 NULL 当 0。如果业务需要把缺考按 0 分算,必须显式写 COALESCE(score, 0)

六、排序、唯一约束和默认值也要小心

不同数据库对 NULL 排序位置可能有差异,有的默认在前,有的默认在后,也可能支持 NULLS FIRST/LAST

SELECT id, score
FROM exams
ORDER BY score DESC NULLS LAST;

唯一约束中 NULL 的行为也依赖数据库实现。很多数据库允许唯一列中出现多个 NULL,因为多个未知值不一定相等。

工程设计上,能不用 NULL 表示业务状态时要谨慎。比如订单状态不要用 NULL 表示“待支付”,更适合定义明确枚举值 pendingNULL 更适合确实未知或不存在的数据,如“用户尚未填写生日”。

七、常见误区与追问

  • 误区:NULL = NULL 为真。 两个未知值不能被判断为相等,结果通常是 UNKNOWN
  • 误区:WHERE col != 1 会返回 NULL 行。 NULL != 1 也是 UNKNOWN,不会被 WHERE 保留。
  • 误区:COUNT(col)COUNT(*) 一样。 前者只统计非空列值,后者统计行数。
  • 误区:NOT IN 子查询里有 NULL 没影响。 它可能让结果整体变成 UNKNOWN,导致查不到预期数据。
  • 追问:如何把 NULL 当默认值处理? 使用 COALESCE(col, default_value)
  • 追问:如何判断空字符串? 空字符串和 NULL 不是一回事,通常用 col = '' 判断空字符串,用 IS NULL 判断空值。

八、加强记忆

NULL 题要抓住“未知”二字:比较会产生 UNKNOWNWHERE 只要 TRUECOUNT(col) 跳过空值,NOT IN 遇空值容易翻车。写 SQL 时看到空值相关条件,第一反应应是 IS NULLIS NOT NULLCOALESCENOT EXISTS