0Pricing
SQL Interview Prep · 课时

查找没有匹配项的行(反连接)

使用 LEFT JOIN / IS NULL 模式查找孤立记录和缺失数据

查找没有匹配项的行(反连接) 是 CoddyKit 上的免费 SQL Interview Prep 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 SQL Interview Prep 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 SQL Interview Prep 课程共包含 4 节课。

反连接问题

外连接中最常被问到的问题之一是:“查找从未下过订单的客户。”或者:“列出从未售出的产品,”以及“没有匹配客户的订单。”

这些问题都有同一种结构:一张表中在另一张表里没有匹配项的行。简洁的惯用写法是反连接,即使用 LEFT JOIN 加上 IS NULL 筛选条件。

核心思路

从 LEFT JOIN 开始:它会保留左表的每一行,而未匹配的左表行会在右表列中得到 NULL。

因此,未匹配的行恰好就是右表某列为 NULL 的行。筛选这些行,就能单独找出没有匹配项的行。这就是全部技巧。

构建这一模式

下面是查找没有订单的客户时使用的规范反连接写法。请分两步阅读:LEFT JOIN 保留所有客户,然后 WHERE o.customer_id IS NULL 只保留未匹配的客户。

SELECT c.id, c.name
FROM customers c
LEFT JOIN orders o
  ON o.customer_id = c.id
WHERE o.customer_id IS NULL;
-- only customers with zero orders

为什么它能逐步奏效

用我们的数据跟踪整个过程,其中 Carol 没有订单:

  • LEFT JOIN 生成 Alice(x2)、Bob(x1),以及右侧列为 NULL 的 Carol。
  • WHERE o.customer_id IS NULL 会丢弃 Alice 和 Bob(他们的右侧列包含实际值)。
  • 只有 Carol 的行,也就是合成 NULL 的那一行,会保留下来。

筛选是在连接之后运行的,因此它能看到这些 NULL,并准确选出孤立行。

选择要检查的正确列

请检查右表中在真实匹配时绝不可能合法为 NULL 的列,最好是连接键或主键。

如果检查 o.shipped_at 这样的可为 NULL 的右表列,您还会选出确实存在但尚未发货的订单,这是错误答案。检查 o.customer_id(连接键)或 o.id(其主键),就能保证 NULL 表示“没有匹配到行”。

-- SAFE: join key / primary key
WHERE o.id IS NULL

-- RISKY: a nullable data column
WHERE o.shipped_at IS NULL  -- catches unshipped too!

反连接与 NOT IN

面试官经常会将反连接与 NOT IN 进行比较。它们看起来等价,但对 NULL 的处理不同。

如果子查询返回任何一个 NULL,NOT IN 就会完全不返回任何行,这是一个臭名昭著的隐蔽错误。LEFT JOIN / IS NULL 反连接不会受到这个问题的影响。

-- DANGEROUS if any customer_id is NULL
SELECT id, name FROM customers
WHERE id NOT IN (SELECT customer_id FROM orders);

-- SAFE anti-join, same intent
SELECT c.id, c.name FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
WHERE o.id IS NULL;

反连接与 NOT EXISTS

另一种等价写法是使用带有关联子查询的 NOT EXISTS。它同样能正确处理 NULL,而且通常同样快速。

这三种写法(LEFT JOIN/IS NULL、NOT EXISTS、NOT IN)都能表达反连接,但在面试中请优先使用 LEFT JOIN/IS NULL 或 NOT EXISTS,因为它们能安全处理 NULL。提到 NOT IN 的陷阱可以加分。

SELECT c.id, c.name
FROM customers c
WHERE NOT EXISTS (
  SELECT 1 FROM orders o
  WHERE o.customer_id = c.id
);

常见错误

一个常见错误是:把无匹配条件放在 ON 子句中,而不是放在 WHERE 子句中。

写成 ... ON o.customer_id = c.id AND o.id IS NULL 并不会筛选结果;它只会改变匹配条件,而每个客户仍然会通过 LEFT JOIN 保留下来。IS NULL 检查必须放在 WHERE 中,并在连接之后应用。下一课会完整讲解这个陷阱。

查找孤立的子行

这个模式反向也适用。若要查找引用了缺失客户的订单(孤立行,也是一项数据完整性检查),请保留订单表,并检查客户一侧是否为 NULL。

SELECT o.id AS order_id, o.customer_id
FROM orders o
LEFT JOIN customers c
  ON c.id = o.customer_id
WHERE c.id IS NULL;
-- orders pointing to a non-existent customer

统计孤立行

很多时候,需求只是进行计数:“有多少客户从未下过订单?”您可以将反连接包装起来,也可以直接计数。

由于反连接已经为每个孤立客户返回一行,因此在这里直接使用 COUNT(*) 是正确的,因为每个未匹配客户恰好对应一行。

SELECT COUNT(*) AS never_ordered
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
WHERE o.id IS NULL;

可复用模板

请记住下面这个三行骨架;它能解决大量面试问题:

  • FROM keep_table k
  • LEFT JOIN other o ON o.fk = k.id
  • WHERE o.id IS NULL

替换表和键,就能查找未售出的产品、未分配的工单、从未登录的用户,以及任何被描述为“没有匹配 Y 的 X”的问题。

快速检查

您需要查找从未出现在订单明细中的产品。

回顾

反连接用于查找没有匹配项的行:先使用 LEFT JOIN,再使用 WHERE right_key IS NULL。

  • 检查连接键或主键,绝不要检查可为 NULL 的数据列。
  • IS NULL 检查应放在 WHERE 中,而不是 ON 中。
  • 它与 NOT EXISTS 等价;应优先于 NOT IN,因为后者遇到 NULL 时会出问题。
  • 交换两张表,就能查找孤立的子行。

一个模板可以解决许多问题:“没有匹配 Y 的 X”。

常见问题解答

「查找没有匹配项的行(反连接)」课时是免费的吗?

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

「查找没有匹配项的行(反连接)」这节课中我会学到什么?

使用 LEFT JOIN / IS NULL 模式查找孤立记录和缺失数据 你通过在浏览器中直接运行的动手代码来练习 SQL Interview Prep,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

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

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

「查找没有匹配项的行(反连接)」课时需要多长时间?

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

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

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

此课程中的所有课时

  1. LEFT JOIN 与保留未匹配行
  2. RIGHT 和 FULL OUTER JOIN 语义
  3. 查找没有匹配项的行(反连接)
  4. 外连接中的 WHERE 筛选陷阱
← 返回 SQL Interview Prep