SQL 中的子查询和 CTE

发布: (2026年4月22日 GMT+8 04:51)
5 分钟阅读
原文: Dev.to

Source: Dev.to

在使用 SQL 时,你最终会遇到单个查询不足以解决的情况。你需要将问题拆分成多个部分,计算一个中间结果,然后在其他地方使用该结果。这时子查询和公共表表达式(CTE)就派上用场了。

它们解决类似的问题,但方式略有不同,选择使用哪一种会影响性能、可读性和可维护性。

子查询

子查询是写在另一个查询内部的查询。它产生的结果供外部查询使用——本质上是一个问题中的问题。

子查询的工作原理

  • 位置:通常嵌入在 WHERESELECTFROM 子句中,具体取决于其作用。
  • 使用场景:快速计算或过滤,仅在一次需要结果时使用。

子查询的类型

TypeDescriptionTypical Use
Scalar subquery返回单个值比较(例如 WHERE salary > (SELECT AVG(salary) FROM employees)
Multi‑row subquery返回多个值IN 操作符(例如 WHERE department_id IN (SELECT id FROM departments)
Correlated subquery引用外部查询的列;对每行执行一次复杂过滤;如果没有适当的索引可能会更慢
Nested subquery子查询嵌套在另一个子查询内部有效,但可能难以阅读;通常是需要重构的信号

何时使用子查询

  • 逻辑相对简单。
  • 中间结果只需要使用一次。
  • 想要一个紧凑的查询,而不需要额外的命名。

公共表表达式 (CTE)

CTE 是在查询开头定义的具名临时结果集。你只需定义一次,然后在整个查询中通过名称引用它。

CTE 的优势

  • 通过将逻辑划分为具名部分,提高可读性。
  • 允许一步步构建查询;一个 CTE 可以依赖另一个 CTE。
  • 可以多次复用同一中间结果。
  • 支持递归,用于处理层级数据(例如组织结构图、分类树)。

CTE 的类型

  • 简单 CTE – 为单一逻辑块提升可读性。
  • 多个 CTE – 对复杂转换采用分层方式;每个 CTE 可以基于前一个构建。
  • 递归 CTE – 通过反复引用自身来处理层级数据。

比较:子查询 vs. CTE

方面子查询CTE(公共表表达式)
可读性随着嵌套层次增加,可能变得难以跟踪结构化的自上而下流程;更易调试
性能简单子查询通常经过良好优化;相关子查询可能代价高昂可能会被物化,取决于 DBMS;性能因情况而异
可复用性通常内联编写;若在多个位置需要则会出现重复定义一次,可多次引用
复杂度适用于简单、一次性的计算更适合包含多步骤或递归的复杂查询
层次结构对层次数据并不理想递归 CTE 在层次查询中表现出色

实际上,性能更多取决于查询设计和索引,而不是子查询与 CTE 之间的选择。

何时使用每种方式?

  • 子查询:当任务简单、结果只需要一次、并且你偏好紧凑的查询时选择。
  • 公共表表达式(CTE):当逻辑复杂、可读性重要、需要复用中间结果,或处理需要递归的层次数据时更适合。

子查询和 CTE 是互补的工具,而非直接竞争对手。通常会先使用子查询,随着查询复杂度提升再切换到 CTE,以获得更清晰、更易维护的 SQL。

0 浏览
Back to Blog

相关文章

阅读更多 »

mdka v2 发布

发布 我们已经发布了 mdka 的 v2 版本(https://github.com/nabbisen/mdka-rs),这是一款基于 Rust 的 HTML 转 Markdown 转换器。最初它是作为 o… 的核心组件开发的。