0Pricing
Coding Interview Prep · 课时

LEFT JOIN 与保留未匹配行

了解 LEFT JOIN 会保留哪些内容,以及不匹配行中如何出现 NULL

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

面试场景

面试官说:“列出每位客户及其订单,包括从未下过订单的客户。”INNER JOIN 会丢弃没有订单的客户,因此无法满足这个要求。这里应使用 LEFT JOIN。

LEFT JOIN 会保留左侧(首先写出的)表中的每一行,并在右表存在匹配行时附加这些行。本课将帮助您建立面试官所期望的准确思维模型。

LEFT JOIN 的保证

核心保证是:左表中的每一行都会至少在输出中出现一次,无论是否匹配。

  • 如果左表中的一行在右表找到匹配项,输出中会为每个匹配项生成一行。
  • 如果左表中的一行没有找到匹配项,输出中仍会有一行,并且右表的所有列都会设为 NULL。

这就是面试官称其为外连接的原因:匹配集合之外的行会被保留,而不是丢弃。

两张表

本课始终使用两张简单的表。customers 包含所有客户;orders 记录购买行为,并通过 customer_id 引用客户。

请注意,客户 3(卡罗尔)在 orders 中没有对应的行。这个未匹配的客户正是 LEFT JOIN 必须保留的对象。

-- customers
-- id | name
--  1 | Alice
--  2 | Bob
--  3 | Carol

-- orders
-- id | customer_id | amount
-- 10 |     1       |  50
-- 11 |     1       |  75
-- 12 |     2       |  20

编写 LEFT JOIN

语法与 INNER JOIN 类似,只需将 INNER 换成 LEFT(OUTER 这个词可以省略:LEFT JOIN 和 LEFT OUTER JOIN 完全相同)。

在 JOIN 关键字之前写出的表就是被保留的左侧。顺序很重要:customers LEFT JOIN orders 会保留所有客户,而不是所有订单。

SELECT c.name, o.amount
FROM customers c
LEFT JOIN orders o
  ON o.customer_id = c.id;

读取结果

下面是该查询的输出结果。爱丽丝匹配了两次,因此出现两行。鲍勃匹配了一次。卡罗尔没有匹配到任何内容,因此仍然会出现,并且 amount 列的值为 NULL。

这唯一一行带有 NULL 的卡罗尔记录,就是 LEFT JOIN 的典型特征。面试官希望听到您这样解释:“未匹配的左表行会保留,右表列则为 NULL。”

-- name  | amount
-- Alice |  50
-- Alice |  75
-- Bob   |  20
-- Carol | NULL   <-- preserved, no match

NULL 从何而来

这个 NULL 并没有存储在任何地方。由于没有右表行可以提供 amount,数据库会合成它。

对于未匹配的左表行,从右表获取的每一列都会变成 NULL:o.id、o.customer_id 和 o.amount 在卡罗尔这一行中都为 NULL。这一点很重要,因为 o.customer_id 为 NULL 并不意味着该客户没有 ID,而是意味着根本没有匹配的订单。

统计每位客户的订单数

一个常见的后续问题是:“如何统计每位客户的订单数,包括订单数为零的客户?”使用 LEFT JOIN 加上 COUNT 就能准确实现,但您必须统计右表的列,而不是 *。

COUNT(o.id) 会忽略 NULL,因此卡罗尔的结果为 0。COUNT(*) 则会错误地为卡罗尔返回 1,因为合成的 NULL 行仍然会被计为一行。

SELECT c.name, COUNT(o.id) AS order_count
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
GROUP BY c.name;
-- Alice | 2
-- Bob   | 1
-- Carol | 0

COUNT(*) 与 COUNT(列) 的陷阱

这是一个经典的面试陷阱。LEFT JOIN 之后,未匹配的左表行会实际存在于结果中,只是右表列为 NULL。

  • COUNT(*) 会统计这一行,因此对于没有订单的客户返回 1。
  • COUNT(o.id) 会跳过 NULL,因此正确返回 0。

当您需要得到真正的零值时,请始终统计在无匹配一侧会为 NULL 的列。

-- WRONG: Carol shows 1
SELECT c.name, COUNT(*) AS n
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
GROUP BY c.name;

使用 LEFT JOIN 求和

除了 COUNT 之外的聚合函数也能妥善处理合成的 NULL 值。SUM 会忽略 NULL,因此未匹配的客户会得到 NULL(不会报错)。

面试官通常希望报表显示零而不是 NULL。请将聚合函数包在 COALESCE 中,以替换默认值。

SELECT c.name,
       COALESCE(SUM(o.amount), 0) AS total_spent
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
GROUP BY c.name;
-- Alice | 125
-- Bob   |  20
-- Carol |   0

清楚说明左表与右表

当面试官问“哪张表会被保留?”时,请自信地回答:JOIN 关键字左侧的表。请从左到右阅读。

A LEFT JOIN B = 保留 A 的全部内容。如果要保留 B 的全部内容,可以改写为 B LEFT JOIN A,也可以使用 RIGHT JOIN。为了提高可读性,大多数团队只使用 LEFT JOIN,直接重新排列表的顺序。

思维检查清单

在面试中看到 LEFT JOIN 时,请大声说出以下检查清单:

  • 保留哪一侧?左表,所有行都会保留。
  • 未匹配的行?出现一次,并带有来自右表的 NULL 值。
  • 统计数量?使用 COUNT(right_col) 才能得到真正的零值。
  • 求和?如果需要 0 而不是 NULL,请使用 COALESCE 包装。

能够清晰说出这份检查清单,体现出高级水平的严谨性。

快速检查

通过统计来测试您对 LEFT JOIN 的直觉。

回顾

LEFT JOIN 会保留左表中的每一行。已匹配的左表行会与右表的匹配行配对;未匹配的左表行会保留一次,并且右表的所有列都为 NULL。

  • 左表就是位于 JOIN 关键字之前的表。
  • 合成的 NULL 值标记了没有匹配项的行。
  • COUNT(right_col) 能得到真正的零值;COUNT(*) 不能。
  • COALESCE(SUM(...), 0) 会将 NULL 总计转换为零。

这是后续课程中查找缺失数据和反连接的基础。

常见问题解答

「LEFT JOIN 与保留未匹配行」课时是免费的吗?

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

「LEFT JOIN 与保留未匹配行」这节课中我会学到什么?

了解 LEFT JOIN 会保留哪些内容,以及不匹配行中如何出现 NULL 你通过在浏览器中直接运行的动手代码来练习 Coding Interview Prep,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

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

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

「LEFT JOIN 与保留未匹配行」课时需要多长时间?

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

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

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

此课程中的所有课时

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