健康一贴灵,专注医药行业管理信息化

SQL关键字三分钟入门:WITH —— 公用表表达式让复杂查询更清晰

转自:https://blog.csdn.net/Landcc/article/details/148765844

在实际的数据库开发和分析中,我们常常会遇到复杂的多层嵌套查询,这样的 SQL 语句不仅难以阅读,也容易出错。

这时候就需要使用一个非常实用又优雅的关键字 —— WITH

它可以帮助我们将复杂的子查询提取出来并命名,从而提升代码可读性、复用性和维护性。这个功能也被称为 CTE(Common Table Expressions,公用表表达式)


 1.什么是 WITH?

WITH 是 SQL 中用于定义临时结果集的关键字。这些临时结果集可以在后续查询中像普通表一样被引用,并且只在当前查询执行期间存在。

你可以把它理解为:“先写好一个中间结果,后面可以直接拿来用”。


 2.基本语法

  1. WITH cte_name AS (
  2. -- 子查询内容
  3. SELECT ...
  4. )
  5. -- 后续主查询中使用 cte_name
  6. SELECT * FROM cte_name;
sql
  • cte_name 是你给中间结果集起的名字。
  • 可以定义多个 CTE,用逗号分隔。

 3.示例讲解

假设我们有一个 orders 表,记录了订单信息:

order_idcustomer_idamount
112999
22499
31199
43899

 示例1:计算每个客户的订单总金额(简单 CTE 使用)

  1. WITH customer_totals AS (
  2. SELECT customer_id, SUM(amount) AS total_amount
  3. FROM orders
  4. GROUP BY customer_id
  5. )
  6. SELECT *
  7. FROM customer_totals
  8. WHERE total_amount > 500;
sql
结果:
customer_idtotal_amount
13198
3899

👉 这里我们先定义了一个 CTE customer_totals 来计算每位客户的总消费金额,然后主查询筛选出金额大于500的客户。


 示例2:多个 CTE 的使用(分步处理复杂逻辑)

  1. WITH
  2. -- 第一步:统计每位客户的总消费
  3. customer_totals AS (
  4. SELECT customer_id, SUM(amount) AS total_amount
  5. FROM orders
  6. GROUP BY customer_id
  7. ),
  8. -- 第二步:根据总消费划分客户等级
  9. customer_levels AS (
  10. SELECT customer_id, total_amount,
  11. CASE
  12. WHEN total_amount > 1000 THEN '高级客户'
  13. WHEN total_amount BETWEEN 500 AND 1000 THEN '中级客户'
  14. ELSE '普通客户'
  15. END AS level
  16. FROM customer_totals
  17. )
  18. -- 最终查询:展示客户等级信息
  19. SELECT * FROM customer_levels;
sql
结果:
customer_idtotal_amountlevel
13198高级客户
2499普通客户
3899中级客户

 通过多个 CTE 分步骤处理,整个查询逻辑更加清晰易懂。


 示例3:递归 CTE(以员工层级为例)

递归 CTE 是 WITH 的一种高级用法,常用于处理树形结构或层级数据(如组织架构、分类目录等)。

假设我们有一个 employees 表:

employee_idnamemanager_id
1张三NULL
2李四1
3王五2
  1. WITH RECURSIVE employee_hierarchy AS (
  2. -- 初始查询:没有上级的员工(即 CEO)
  3. SELECT employee_id, name, manager_id, CAST(name AS TEXT) AS hierarchy_path
  4. FROM employees
  5. WHERE manager_id IS NULL
  6. UNION ALL
  7. -- 递归部分:查找下属员工
  8. SELECT e.employee_id, e.name, e.manager_id,
  9. CAST(eh.hierarchy_path || ' → ' || e.name AS TEXT)
  10. FROM employees e
  11. INNER JOIN employee_hierarchy eh ON e.manager_id = eh.employee_id
  12. )
  13. SELECT * FROM employee_hierarchy;
sql
结果:
employee_idnamemanager_idhierarchy_path
1张三NULL张三
2李四1张三 → 李四
3王五2张三 → 李四 → 王五

 这个例子展示了如何用递归 CTE 构建一个组织层级路径,非常适合处理树状结构数据。


对比项使用 WITH(CTE)不使用 CTE(嵌套子查询)
可读性更高,结构清晰较低,嵌套多层时难读
复用性可多次引用每次都要重复写
调试方便性易于单独测试每个 CTE难以调试嵌套部分
递归支持支持(RECURSIVE)不支持
性能与子查询基本一致,但逻辑优化后可能更好视具体实现而定

4. 总结对比表

功能SQL 示例
定义单个 CTEWITH cte AS (...) SELECT * FROM cte;
定义多个 CTEWITH a AS (...), b AS (...) SELECT * FROM a JOIN b...
递归 CTEWITH RECURSIVE ...
提高代码可读性将复杂查询拆分为多个逻辑块
支持重用同一查询中可多次引用 CTE 名
            </div>
posted @ 2025-07-10 14:48  一贴灵  阅读(11)  评论(2)    收藏  举报
学以致用,效率第一