0Pricing
Coding Interview Prep · 课时

SELECT 和 WHERE 中的标量子查询

掌握单值子查询,以及子查询返回多行时产生的错误

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

面试官所说的标量子查询是什么

标量子查询是一个恰好返回一行一列的查询,也就是一个单独的值。由于它会解析为一个值,数据库允许您几乎在任何可以使用字面值的地方使用它:例如 SELECT、WHERE、HAVING,甚至 ORDER BY 中。

  • 面试官会测试您是否了解一行一列这一规则。
  • 经典陷阱是:子查询意外返回了多行。

如果您能清楚地陈述这一定义,就已经通过了第一个检查点。

SELECT 列表中的标量子查询

将标量子查询放入 SELECT 列表,可以为每个输出行附加一个计算得到的单独值。这里会在每位员工旁边显示全公司的平均工资。

子查询 (SELECT AVG(salary) FROM employees) 会运行并将整张表汇总为一个数字,然后在每一行中重复显示这个数字。

SELECT
  name,
  salary,
  (SELECT AVG(salary) FROM employees) AS company_avg
FROM employees;

WHERE 中的标量子查询

同一个单独的值也可以驱动筛选。面试中非常常见的一道题是:找出所有收入高于公司平均水平的人。

子查询会计算一次平均值,然后将外层查询中的每一行与该平均值进行比较。这不是相关子查询——内层查询不依赖外层行,因此只运行一次。

SELECT name, salary
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);

“多于一行”错误

这是面试官希望您能够预判的错误。如果子查询与 = 或 > 一起使用,却返回了多行,数据库引擎就会抛出以下错误:

  • Postgres:作为表达式使用的子查询返回了多行
  • MySQL:子查询返回了多于 1 行

下面的查询会失败,因为部门 5 中可能有多名员工——该子查询不是标量子查询。

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

强制使子查询返回标量值

有两种可靠的方法可以保证只得到一个值:

  • 使用 MAX、MIN 或 AVG 等聚合函数——不带 GROUP BY 的聚合函数始终返回一行。
  • 在 ORDER BY 之后使用 LIMIT 1(Postgres/MySQL)或 FETCH FIRST 1 ROW ONLY。

下面的修正版会请求部门 5 中工资最高的员工的单独工资值。

SELECT name
FROM employees
WHERE salary = (
  SELECT MAX(salary) FROM employees WHERE dept_id = 5
);

没有行时,标量子查询返回 NULL

面试中一个容易忽略的要点是:如果标量子查询匹配到零行,它不会报错——而是返回 NULL。这个 NULL 随后会在比较过程中继续传播。

由于 salary > NULL 的计算结果是 UNKNOWN(而不是真),外层查询不会返回任何行。应试者经常以为这里会报错;正确答案是:结果为空,并且会静默发生。

SELECT name, salary
FROM employees
WHERE salary > (
  SELECT AVG(salary) FROM employees WHERE dept_id = 9999
);

完整示例:找出高于平均工资的员工及其差额

让我们结合这两种用法。我们会显示每位工资高于平均值的员工,以及其工资高出平均值多少。同一个标量子查询同时出现在 SELECT 和 WHERE 中。

面试官可能会问子查询是否运行了两次。从逻辑上看,它确实出现了两次;但优秀的优化器可以只计算一次这个非相关子查询,然后重复使用结果。

SELECT
  name,
  salary,
  salary - (SELECT AVG(salary) FROM employees) AS above_avg
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees)
ORDER BY above_avg DESC;

ORDER BY 中的标量子查询

由于标量子查询本质上只是一个值,因此也可以合法地放在 ORDER BY 中。这通常不是最清晰的写法,但面试官喜欢借此确认您知道这种用法是允许的。

这里不进行连接,而是按照从另一张表中取得的值——每个部门的员工数量——对部门进行排序。

SELECT d.dept_name
FROM departments d
ORDER BY (
  SELECT COUNT(*) FROM employees e WHERE e.dept_id = d.id
) DESC;

标量子查询与相关子查询:厘清界限

上面的 ORDER BY 示例实际上引用了外层查询中的 d.id——这使它成为一个相关标量子查询,并且每个外层行都会运行一次。

面试官非常重视下面这个区别:

  • 非相关标量子查询:自包含,只运行一次。
  • 相关标量子查询:引用外层行,按行运行。

两者仍然都是标量子查询(返回一个值),但性能可能有很大差异。

何时不应使用标量子查询

将相关标量子查询放在 SELECT 列表中很方便,但在大型表上可能较慢——因为它会按行执行。面试官希望您了解以下替代方案:

  • 将 LEFT JOIN 连接到预先聚合的派生表。
  • 使用窗口函数,例如 AVG(salary) OVER ()。

下面的窗口函数写法无需单独扫描子查询,就能生成相同的公司平均工资列。

SELECT
  name,
  salary,
  AVG(salary) OVER () AS company_avg
FROM employees;

面试简洁表述

如果面试官要求您定义标量子查询,可以这样回答:“标量子查询返回一行一列,因此它的作用类似于一个单独的值,可以在允许使用字面值的任何地方使用。如果它返回多行,数据库引擎就会报错;如果它不返回任何行,就会得到 NULL。”

这一句话涵盖了定义、错误情况和 NULL 边界情况——也就是每位面试官都会关注的三个要点。

快速检查

测试您对标量子查询行为的理解。

回顾

现在,您已经掌握了标量子查询:

  • 定义:一行一列——可以像字面值一样用于 SELECT、WHERE、HAVING 和 ORDER BY。
  • 使用 = 或 > 时如果返回多行,就会导致错误;可以通过聚合函数或 LIMIT 1 强制得到标量结果。
  • 零行会产生 NULL,从而在筛选中静默排除相关行。
  • 相关标量子查询会按行运行;当性能很重要时,应优先考虑连接或窗口函数。

下一步:学习 FROM 子句中的子查询,此时结果会成为一整张虚拟表。

常见问题解答

「SELECT 和 WHERE 中的标量子查询」课时是免费的吗?

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

「SELECT 和 WHERE 中的标量子查询」这节课中我会学到什么?

掌握单值子查询,以及子查询返回多行时产生的错误 你通过在浏览器中直接运行的动手代码来练习 Coding Interview Prep,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

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

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

「SELECT 和 WHERE 中的标量子查询」课时需要多长时间?

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

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

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

此课程中的所有课时

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