Coding Interview Prep · 课时

使用连接模拟集合运算

在不支持 EXCEPT 和 INTERSECT 的方言中重写它们

第 4 / 4 课13 个步骤

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

为什么要模拟集合运算

并非每个数据库都支持 INTERSECT 和 EXCEPT。例如,较旧版本的 MySQL 完全不支持它们。面试官会考查您是否能在运算符不可用时,使用连接和子查询重现集合逻辑。

同时了解集合运算符及其等价的连接写法,能够证明您理解该运算符实际计算的内容。

将 INTERSECT 实现为 INNER JOIN

INTERSECT 会找出两个集合共有的行。等价的连接写法是在所有待比较列上使用 INNER JOIN,并加上 DISTINCT 以匹配去重行为。

比较中的每一列都会成为连接谓词的一部分。

-- A INTERSECT B emulated:
SELECT DISTINCT a.customer_id
FROM orders_2023 a
JOIN orders_2024 b
  ON a.customer_id = b.customer_id;

为什么 INTERSECT 需要 DISTINCT

普通的 INNER JOIN 可能会产生扇出:如果某个值在任一侧出现多次,连接会使行数成倍增加。标准 INTERSECT 会使每个共同的行只返回一次,因此需要添加 DISTINCT 来合并连接引入的重复行。

忘记在这里使用 DISTINCT 是面试中的常见失误。

-- without DISTINCT, a customer with 3 orders in each year
-- would appear 9 times from the join

EXCEPT 的 LEFT JOIN / IS NULL 写法

EXCEPT(A 中有而 B 中没有)就是反连接。可移植的写法是:从 A 到 B 按所有列执行 LEFT JOIN,只保留 B 侧为 NULL(没有匹配)的行,然后使用 DISTINCT。

这种 LEFT JOIN / IS NULL 模式是 SQL 面试中最常复用的技巧之一。

SELECT DISTINCT a.customer_id
FROM orders_2023 a
LEFT JOIN orders_2024 b
  ON a.customer_id = b.customer_id
WHERE b.customer_id IS NULL;

EXCEPT 与 NOT EXISTS

同样可移植的 EXCEPT 写法是使用 NOT EXISTS。它的含义是“保留每一行 A,前提是不存在匹配的 B 行”,并且能够稳健地处理 NULL。

许多工程师更喜欢 NOT EXISTS,因为它的意图很明确,也能避开 NOT IN + NULL 陷阱。

SELECT DISTINCT a.customer_id
FROM orders_2023 a
WHERE NOT EXISTS (
  SELECT 1 FROM orders_2024 b
  WHERE b.customer_id = a.customer_id
);

INTERSECT 与 EXISTS

同理,INTERSECT 可以使用 EXISTS 来写:保留每一行不重复的 A,前提是存在匹配的 B 行。

EXISTS 会在首次匹配时提前结束,因此可能更高效,也能避免连接扇出,有时还可以不必在连接侧使用 DISTINCT。

SELECT DISTINCT a.customer_id
FROM orders_2023 a
WHERE EXISTS (
  SELECT 1 FROM orders_2024 b
  WHERE b.customer_id = a.customer_id
);

NOT IN 的 NULL 陷阱

一种看似合理的 EXCEPT 模拟方式是 NOT IN,但它很危险:如果子查询返回任意 NULL 值,NOT IN 将完全不返回任何行,因为比较结果会变成 UNKNOWN。

这是一个经常被测试的易错点。请优先使用 NOT EXISTS 或 LEFT JOIN / IS NULL,它们能够安全处理 NULL。

-- RISKY if orders_2024.customer_id can be NULL:
SELECT DISTINCT customer_id FROM orders_2023
WHERE customer_id NOT IN (
  SELECT customer_id FROM orders_2024
);

在多个列上进行匹配

当集合比较涉及多个列时,每一列都必须参与连接谓词。对于反连接,您还必须处理这些列中可能存在 NULL 的情况,这正是 NOT EXISTS 的优势所在。

请在 ON 子句中明确写出每一列;漏掉一列会悄然改变“相等行”的定义。

SELECT DISTINCT a.id, a.city
FROM a
LEFT JOIN b
  ON a.id = b.id AND a.city = b.city
WHERE b.id IS NULL;

不使用运算符模拟 UNION

UNION ALL 就是拼接,每种方言都直接支持它。要在需要时模拟去重后的 UNION,可在子查询中使用 UNION ALL 进行拼接,再用 SELECT DISTINCT 包裹,或对所有列执行 GROUP BY。

这说明 UNION 其实就是 UNION ALL 加上去重步骤。

SELECT DISTINCT * FROM (
  SELECT city FROM a
  UNION ALL
  SELECT city FROM b
) combined;

选择合适的模拟方式

决策指南:

  • INTERSECT → EXISTS 或 INNER JOIN + DISTINCT。
  • EXCEPT → NOT EXISTS 或 LEFT JOIN / IS NULL。
  • 当可能存在 NULL 值时,避免使用 NOT IN。
  • UNION → 在 DISTINCT 中包裹 UNION ALL。

EXISTS / NOT EXISTS 是最具可移植性且能安全处理 NULL 的写法,因此是面试中最稳妥的回答。

串联起来

能够将集合运算符转换为连接,说明您理解的是集合逻辑,而不只是语法。反连接(LEFT JOIN / IS NULL 或 NOT EXISTS)是最有价值的模式:它既会出现在 EXCEPT 模拟中,也会出现在查找孤儿记录和缺失记录的问题中。

请先以 NOT EXISTS 开头以确保正确性,然后在讨论性能时提到连接写法。

快速检查

您的数据库不支持 EXCEPT。您需要找出 orders_2023 中不在 orders_2024 中的 customer_ids,并且该列可能包含 NULL 值。

回顾

关键要点:

  • INTERSECT → INNER JOIN + DISTINCT,或 EXISTS。
  • EXCEPT → LEFT JOIN / IS NULL,或 NOT EXISTS(反连接)。
  • 添加 DISTINCT,以匹配集合运算符的去重行为,并抑制连接扇出。
  • 在可能存在 NULL 值时避免使用 NOT IN;优先使用 NOT EXISTS。
  • UNION = 在 DISTINCT 中包裹 UNION ALL。
免费开始

用 AI 导师学习 Coding Interview Prep — 免费

在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。

课程
90
课程
360

常见问题解答

「使用连接模拟集合运算」课时是免费的吗?

是的 — 「使用连接模拟集合运算」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Coding Interview Prep 课程的其余内容,请升级到 CoddyKit PRO。 Coding Interview Prep 课程共包含 4 节课。

「使用连接模拟集合运算」这节课中我会学到什么?

在不支持 EXCEPT 和 INTERSECT 的方言中重写它们 你通过在浏览器中直接运行的动手代码来练习 Coding Interview Prep,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

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

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

「使用连接模拟集合运算」课时需要多长时间?

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

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

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

此课程中的所有课时

  1. UNION 与 UNION ALL
  2. 列数与类型兼容性
  3. 使用 INTERSECT 和 EXCEPT 进行比较
  4. 使用连接模拟集合运算
← 返回 Coding Interview Prep