0Pricing
SQL Interview Prep · 课时

IN、ANY 和 ALL 子查询

掌握集合成员子查询,以及 NOT IN 遇到 NULL 的经典陷阱

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

集合成员关系子查询

当子查询返回一个值列表时,可以使用 IN、ANY 或 ALL 判断某个值是否属于该列表。这些运算符用于判断这个值是否在该集合中,或者它是否大于该集合中的所有元素或任一元素。

  • IN — 匹配列表中的任意值。
  • ANY/SOME — 只要比较条件对至少一个元素成立,结果就为真。
  • ALL — 只有比较条件对每个元素都成立,结果才为真。

使用子查询的 IN

最常见的情况是:查找在位于 'NYC' 的任意部门工作的员工。子查询返回一组部门标识符,IN 保留与其中任意一个标识符匹配的行。

这种写法读起来很自然,也是面试官通常首先期待看到的形式。

SELECT name
FROM employees
WHERE dept_id IN (
  SELECT id FROM departments WHERE city = 'NYC'
);

= ANY 等同于 IN

面试官喜欢考的一种巧妙等价关系是:= ANY (subquery) 与 IN (subquery) 的含义完全相同。当值等于集合中的至少一个元素时,二者的结果都为真。

下面的查询与上一个查询返回完全相同的结果。ANY 及其同义词 SOME 还可以将这种判断推广到 >、< 等其他运算符。

SELECT name
FROM employees
WHERE dept_id = ANY (
  SELECT id FROM departments WHERE city = 'NYC'
);

使用比较运算符的 ANY

ANY 与 > 或 < 搭配时非常强大。salary > ANY (set) 在薪资高于至少最小元素时为真,也就是高于最小值。

这可以找出薪资高于部门 5 中至少一人的员工。

SELECT name, salary
FROM employees
WHERE salary > ANY (
  SELECT salary FROM employees WHERE dept_id = 5
);

使用比较运算符的 ALL

salary > ALL (set) 只有在薪资高于每个元素时才为真,也就是高于最大值。这可以找出薪资超过部门 5 中所有人的员工。

请记住这个快捷规则:> ALL = 大于 MAX,> ANY = 大于 MIN。面试官经常考这一点。

SELECT name, salary
FROM employees
WHERE salary > ALL (
  SELECT salary FROM employees WHERE dept_id = 5
);

NOT IN:著名的 NULL 陷阱

这是子查询面试题中最常见的陷阱。如果 NOT IN 中的子查询返回哪怕一个 NULL,整个 NOT IN 都可能返回零行 — 而不是您原本期待的孤立记录。

为什么?x NOT IN (1, 2, NULL) 会展开为 x <> 1 AND x <> 2 AND x <> NULL。最后一个比较的结果是 UNKNOWN,因此 AND 条件永远不可能为真。

SELECT name
FROM customers
WHERE id NOT IN (
  SELECT customer_id FROM orders
);

查询为何会悄然失效

如果 orders.customer_id 允许为 NULL,并且其中任意一行的值为 NULL,那么即使确实存在没有订单的客户,上一个查询也会返回零行。

  • NULL 的存在会使逻辑结果变为 UNKNOWN。
  • 它不会报错 — 只是返回错误的(空)结果。

在面试中主动说出这一风险,会给面试官留下很好的印象。

修复含 NULL 的 NOT IN

面试官认可的三种安全修复方式:

  • 在子查询中排除 NULL:添加 WHERE customer_id IS NOT NULL。
  • 改写为 NOT EXISTS,它能够正确处理 NULL。
  • 使用 LEFT JOIN ... IS NULL 反连接。

下面这个添加保护条件的版本会返回真正没有订单的客户列表。

SELECT name
FROM customers
WHERE id NOT IN (
  SELECT customer_id FROM orders
  WHERE customer_id IS NOT NULL
);

IN 可以正常处理 NULL

一个令人放心的对比是:普通的 IN(未取反)不会因为列表中含有 NULL 而失效。x IN (1, 2, NULL) 在 x 等于 1 或 2 时为真;NULL 只是不可能匹配成功。

NULL 带来的风险只针对 NOT IN。了解这两种情况的区别,正是自信作答与凭猜测作答的差别。

多列 IN

某些数据库方言(PostgreSQL、MySQL)允许对列元组使用 IN,一次匹配多个列组成的组合。下面的写法可以找出其(产品、地区)组合出现在促销表中的订单明细。

SQL 服务器不支持行值 IN;在那里需要改写为 EXISTS。提到这一可移植性差异,会给面试官留下深刻印象。

SELECT *
FROM order_lines
WHERE (product_id, region) IN (
  SELECT product_id, region FROM promotions
);

面试金句

可以这样说:“IN 用于判断集合成员关系,并且等同于 = ANY。与比较运算符搭配时,> ANY 表示大于最小值,> ALL 表示大于最大值。最大的陷阱是针对可能返回 NULL 的子查询使用 NOT IN — 它会悄悄返回零行,因此我会使用 IS NOT NULL 加以保护,或者改用 NOT EXISTS。”

这段回答一句话涵盖了集合成员关系、ANY/ALL 的语义以及 NULL 陷阱。

快速检查

面试官最喜欢考的子查询陷阱。

回顾

集合成员关系子查询,掌握:

  • IN = = ANY:匹配集合中的任意元素。
  • > ANY 表示大于最小值;> ALL 表示大于最大值。
  • 如果子查询中包含 NULL,NOT IN 会悄悄返回零行 — 使用 IS NOT NULL 加以保护,或改用 NOT EXISTS。
  • 普通 IN 可以处理 NULL;多列 IN 只在某些数据库方言中可用。

下一节:EXISTS 与 IN 的比较,以及资深面试环节常考的性能问题。

常见问题解答

「IN、ANY 和 ALL 子查询」课时是免费的吗?

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

「IN、ANY 和 ALL 子查询」这节课中我会学到什么?

掌握集合成员子查询,以及 NOT IN 遇到 NULL 的经典陷阱 你通过在浏览器中直接运行的动手代码来练习 SQL Interview Prep,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

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

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

「IN、ANY 和 ALL 子查询」课时需要多长时间?

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

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

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

此课程中的所有课时

  1. SELECT 和 WHERE 中的标量子查询
  2. FROM 子句中的子查询(派生表)
  3. IN、ANY 和 ALL 子查询
  4. EXISTS 与 IN 的性能比较
← 返回 SQL Interview Prep