0Pricing
SQL Interview Prep · 课时

三值逻辑与 UNKNOWN

了解 NULL = NULL 为什么不为 TRUE,以及 UNKNOWN 如何在条件中传播

三值逻辑与 UNKNOWN 是 CoddyKit 上的免费 SQL Interview Prep 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 SQL Interview Prep 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 SQL Interview Prep 课程共包含 4 节课。

为什么 NULL 会让候选人答错

NULL 是结构化查询语言面试中错误答案的首要来源。陷阱在于把它当作普通值,而实际上 NULL 表示“未知”或“缺失”,既不是零,也不是空字符串。

面试官喜欢考查这一点,因为语法看起来正确,但结果会悄然出错。他们可能会给您一个“应该”返回某行的筛选条件,然后问您为什么它什么也没有返回。

本课将帮助您建立能够化解所有 NULL 问题的思维模型:三值逻辑。一旦您理解比较结果可能是 TRUE、FALSE 或 UNKNOWN,后面的内容就顺理成章了。

NULL 不是值

面试中最重要的一句话是:NULL 表示没有值,而不是值本身。

这意味着您不能像比较数字那样使用 = 来比较它。数据库无法确定两个未知值是否相等,因此不会断言结果是 TRUE 还是 FALSE。

  • NULL = 5 不是 FALSE,而是 UNKNOWN
  • NULL = NULL 不是 TRUE,而是 UNKNOWN
  • NULL <> NULL 同样是 UNKNOWN

这就是可为空列上的简单等值筛选会悄悄排除行的原因。

二值逻辑与三值逻辑

大多数编程语言使用二值逻辑:表达式要么是 TRUE,要么是 FALSE。只要比较中涉及 NULL,结构化查询语言就会增加第三种结果:UNKNOWN。

因此,结构化查询语言中的任何谓词都可能计算出三种结果之一:TRUE、FALSE 或 UNKNOWN。WHERE 子句只保留其谓词恰好为 TRUE 的行。对于筛选来说,UNKNOWN 的行为类似 FALSE,但从逻辑上看二者并不相同。

面试官会考查您是否了解这一差异,因为 UNKNOWN 在 NOT 下的行为与 FALSE 不同。

会悄悄排除行的筛选条件

下面是一个经典的完整示例。假设 bonus 有时为 NULL。招聘人员问道:“这个查询应该返回奖金不是 1000 的所有人。为什么没有奖金的员工会被跳过?”

对于 bonus 为 NULL 的行,bonus <> 1000 的结果是 UNKNOWN,而不是 TRUE。WHERE 只保留 TRUE 行,因此这些员工就消失了。

解决方法是显式处理 NULL,我们将在下一课中介绍。目前请先认识到,缺失的行是逻辑运算的结果,而不是程序错误。

SELECT name, bonus
FROM employees
WHERE bonus <> 1000;
-- Rows where bonus IS NULL are excluded:
-- NULL <> 1000 evaluates to UNKNOWN, not TRUE

AND 表达式中的 NULL

三值逻辑会改变 AND 的行为。记住下面的规则,您就能当场回答任何真值表问题。

  • TRUE AND UNKNOWN = UNKNOWN
  • FALSE AND UNKNOWN = FALSE
  • UNKNOWN AND UNKNOWN = UNKNOWN

直观地说,AND 只需要一个 FALSE 就能确定结果为 FALSE。因此,FALSE AND 任何值都仍然是 FALSE。但 TRUE AND 未知值仍然是未知,因为未知的一侧最终可能变成任意结果。

-- If status = 'active' is TRUE but bonus = 100 is UNKNOWN:
SELECT *
FROM employees
WHERE status = 'active' AND bonus = 100;
-- Combined result is UNKNOWN, so the row is NOT returned

OR 表达式中的 NULL

OR 的规则与 AND 相对应。它只需要一个 TRUE 就能确定结果为 TRUE,因此 TRUE 会跳过未知结果的影响。

  • TRUE OR UNKNOWN = TRUE
  • FALSE OR UNKNOWN = UNKNOWN
  • UNKNOWN OR UNKNOWN = UNKNOWN

所以,即使某个分支的结果未知,只要另一个分支确实为 TRUE,该行仍然可以匹配 OR 条件。这是继 AND 问题之后经常出现的追问。

SELECT *
FROM employees
WHERE department = 'Sales' OR bonus = 100;
-- A Sales employee with NULL bonus:
-- TRUE OR UNKNOWN = TRUE, so the row IS returned

NOT 会翻转 TRUE/FALSE,但不会翻转 UNKNOWN

这是面试官通常留到最后考查的细节。NOT 会将 TRUE 反转为 FALSE,将 FALSE 反转为 TRUE,但NOT UNKNOWN 仍然是 UNKNOWN。

这就是为什么您不能只是用 NOT 包裹一个失败的条件来翻转结果。如果对于 NULL 行,bonus = 1000 的结果是 UNKNOWN,那么 NOT (bonus = 1000) 的结果也仍然是 UNKNOWN,该行依然会被排除。

否定操作无法挽回 NULL 行,只有显式的 IS NULL 检查才能做到这一点。

-- For a row where bonus IS NULL:
--   bonus = 1000        -> UNKNOWN
--   NOT (bonus = 1000)  -> UNKNOWN  (still excluded)
SELECT * FROM employees WHERE NOT (bonus = 1000);

完整示例:NOT IN 陷阱

这是最常被问到的 NULL 谜题之一。当 NOT IN 的列表包含 NULL 时,它会完全不返回任何行,这会让原本以为它只会跳过 NULL 的候选人感到意外。

在底层,x NOT IN (1, 2, NULL) 会展开为 x <> 1 AND x <> 2 AND x <> NULL。最后一个比较结果是 UNKNOWN,而 TRUE AND TRUE AND UNKNOWN 会归结为 UNKNOWN,因此没有任何内容符合条件。

安全的替代方案是 NOT EXISTS,它不会受到这个问题的影响。

-- Returns ZERO rows if the subquery yields any NULL
SELECT name
FROM employees
WHERE manager_id NOT IN (SELECT manager_id FROM managers);

-- Each comparison against NULL becomes UNKNOWN,
-- and the AND-chain collapses to UNKNOWN for every row.

为什么 UNKNOWN 在 WHERE 中的行为像 FALSE

一个常见的追问是:“如果 UNKNOWN 不是 FALSE,为什么该行会像 FALSE 行一样被排除?”

答案很明确:WHERE、ON 和 HAVING 都采用仅保留 TRUE的规则。FALSE 和 UNKNOWN 都无法通过这一检查,因此在筛选过程中看起来相同。

只有在否定操作和 CHECK 约束中,二者的差异才会显现。CHECK 约束在条件为 TRUE或 UNKNOWN 时会允许行通过,因此 NULL 可能绕过您以为能够阻止它的 CHECK。

-- CHECK passes on TRUE or UNKNOWN, so NULL salary is allowed:
-- CONSTRAINT salary_positive CHECK (salary > 0)
-- INSERT ... salary = NULL  -> NULL > 0 is UNKNOWN -> allowed

深入示例:COUNT 与真值判断的差距

用一个真实的面试题把这些内容串起来:“我们有 100 名员工。SELECT COUNT(*) WHERE bonus = 100 返回 30,而 WHERE bonus <> 100 返回 50。其他 20 名员工去哪儿了?”

缺失的 20 名员工的奖金是 NULL。对于他们,= 100 和 <> 100 都不为 TRUE,而是 UNKNOWN,因此他们完全无法通过这两个筛选条件。

回答“各组数量之和不等于总数,是因为 NULL 不满足任何一个谓词”,正是面试官想听到的答案。

SELECT
  COUNT(*) FILTER (WHERE bonus = 100)  AS eq_100,
  COUNT(*) FILTER (WHERE bonus <> 100) AS ne_100,
  COUNT(*) FILTER (WHERE bonus IS NULL) AS null_bonus,
  COUNT(*) AS total
FROM employees;

面试要点

当谈到 NULL 逻辑时,请说明以下几点,以体现您的资深水平:

  • NULL 表示未知;与它进行比较会得到 UNKNOWN。
  • 结构化查询语言使用三值逻辑:TRUE、FALSE、UNKNOWN。
  • WHERE、ON 和 HAVING只保留 TRUE行。
  • NOT UNKNOWN 仍然是 UNKNOWN,因此否定操作不会找回 NULL 行。
  • 包含任何 NULL 的 NOT IN 都不会返回任何行;请优先使用 NOT EXISTS。

请先说明模型,再演示真值表。这种顺序表明您理解的是原理,而不只是记住了技巧。

快速检查

检验您对三值逻辑的掌握程度。

回顾

现在您已经掌握了 NULL 的核心思维模型:

  • NULL 表示未知,不是值;永远不要使用 = 或 <> 比较它。
  • 结构化查询语言采用三值逻辑:谓词返回 TRUE、FALSE 或 UNKNOWN。
  • 筛选子句只保留 TRUE;UNKNOWN 行会像 FALSE 行一样消失。
  • NOT 会翻转 TRUE 和 FALSE,但不会改变 UNKNOWN。
  • NOT IN 与 NULL 结合会触发陷阱并返回零行;请使用 NOT EXISTS。

下一课将介绍使用 IS NULL、IS NOT NULL 和 NULL 安全等值运算符检查 NULL 的正确方法。

常见问题解答

「三值逻辑与 UNKNOWN」课时是免费的吗?

是的 — 「三值逻辑与 UNKNOWN」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 SQL Interview Prep 课程的其余内容,请升级到 CoddyKit PRO。 SQL Interview Prep 课程共包含 4 节课。

「三值逻辑与 UNKNOWN」这节课中我会学到什么?

了解 NULL = NULL 为什么不为 TRUE,以及 UNKNOWN 如何在条件中传播 你通过在浏览器中直接运行的动手代码来练习 SQL Interview Prep,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 SQL Interview Prep 需要有经验吗?

无需任何先前经验。CoddyKit 上的 SQL Interview Prep 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。

「三值逻辑与 UNKNOWN」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 SQL Interview Prep 课中编写并运行代码吗?

能。每节 SQL Interview Prep 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 三值逻辑与 UNKNOWN
  2. IS NULL、IS NOT NULL 与 NULL 安全相等
  3. COALESCE、NULLIF 与 ISNULL
  4. 汇总、连接和 DISTINCT 中的 NULL
← 返回 SQL Interview Prep