SQL 实战:使用 CTE(公用表达式)优化递归与多层复杂查询

公用表表达式(Common Table Expression,CTE) 是 SQL 中用于简化复杂查询和递归操作的强大工具。CTE 提供了一种临时结果集,可以在查询中多次引用,避免重复代码,提高查询的可读性和维护性。

CTE 主要应用于以下场景:

  1. 递归查询:生成层级关系树,如员工上下级关系、用户推荐关系等。
  2. 分层累计计算:实现逐层汇总与动态累计。
  3. 复杂子查询优化:通过 CTE 拆分复杂的多层嵌套查询,提高执行效率。

一、CTE 语法与基本概念

1. CTE 语法结构
sql 复制代码
WITH cte_name AS (  
    SELECT column1, column2  
    FROM table_name  
    WHERE condition  
)  
SELECT * FROM cte_name;

说明

  • WITH 关键字用于定义 CTE,cte_name 是 CTE 名称。
  • CTE 可以作为子查询使用,后续主查询可以直接调用 CTE。

2. 递归 CTE 语法
sql 复制代码
WITH RECURSIVE cte_name AS (  
    -- 基础查询(递归起点)  
    SELECT column1, column2, 1 AS level  
    FROM table_name  
    WHERE condition  
  
    UNION ALL  
  
    -- 递归部分(自引用)  
    SELECT t.column1, t.column2, c.level + 1  
    FROM table_name t  
    JOIN cte_name c  
    ON t.parent_id = c.id  
)  
SELECT * FROM cte_name;

说明

  • 递归 CTE 包括基础查询递归查询 ,通过 UNION ALL 将两部分合并。
  • 递归 CTE 适用于生成树形结构或层次关系的查询。

二、实战案例


案例 1:生成用户推荐关系的递归树

需求描述

在用户管理系统中,每个用户可能通过其他用户推荐注册。我们需要生成用户推荐树,展示层级关系,并计算每个用户对应层级的奖励金额。


表结构 users
user_id name referrer_id amount
1 张三 NULL 1000
2 李四 1 800
3 王五 1 900
4 赵六 2 700
5 孙七 3 500
6 钱八 4 600

需求目标
  • 生成完整的推荐树(用户层级关系)。
  • 计算每个用户的层级。
  • 汇总每层用户的奖励金额。

SQL 实现
sql 复制代码
WITH RECURSIVE user_tree AS (  
    -- 基础层(顶层推荐人)  
    SELECT user_id, name, referrer_id, amount, 1 AS level  
    FROM users  
    WHERE referrer_id IS NULL  
  
    UNION ALL  
  
    -- 递归计算下级用户  
    SELECT u.user_id, u.name, u.referrer_id, u.amount, t.level + 1  
    FROM users u  
    JOIN user_tree t  
    ON u.referrer_id = t.user_id  
)  
SELECT user_id, name, referrer_id, level, amount  
FROM user_tree  
ORDER BY level, referrer_id;

查询结果
user_id name referrer_id level amount
1 张三 NULL 1 1000
2 李四 1 2 800
3 王五 1 2 900
4 赵六 2 3 700
5 孙七 3 3 500
6 钱八 4 4 600

解释

  • 初始查询筛选出没有推荐人的用户(顶层推荐人)。
  • 递归部分根据 referrer_id 逐层匹配,计算每个用户的层级。
  • level 字段表示用户所在的层级深度。


案例 2:动态计算每层用户奖励金额累计

需求描述

在推荐系统中,每层用户的订单金额需要累计汇总,以便按层级计算奖励发放。


SQL 实现
sql 复制代码
WITH RECURSIVE user_tree AS (  
    SELECT user_id, referrer_id, amount, 1 AS level  
    FROM users  
    WHERE referrer_id IS NULL  
  
    UNION ALL  
  
    SELECT u.user_id, u.referrer_id, u.amount, t.level + 1  
    FROM users u  
    JOIN user_tree t  
    ON u.referrer_id = t.user_id  
),  
amount_summary AS (  
    SELECT level, SUM(amount) AS total_amount  
    FROM user_tree  
    GROUP BY level  
)  
SELECT level, total_amount  
FROM amount_summary  
ORDER BY level;

查询结果
level total_amount
1 1000
2 1700
3 1200
4 600

解释

  • 递归 CTE 生成用户推荐树后,第二个 CTE amount_summary 按层级汇总每层用户的订单金额。
  • 通过 SUM(amount)GROUP BY level 计算每个层级的总金额。


三、复杂子查询优化与简化


案例 3:优化嵌套子查询,提取每个部门的最新员工入职记录

需求描述

在员工管理系统中,每个部门可能有多个员工,我们需要提取每个部门最新入职的员工记录。


表结构 employees
emp_id dept_id emp_name hire_date
101 1 张三 2023-03-01
102 1 李四 2024-01-01
103 2 王五 2024-02-15
104 2 赵六 2023-11-20

SQL 实现
sql 复制代码
WITH latest_hires AS (  
    SELECT dept_id, MAX(hire_date) AS max_hire_date  
    FROM employees  
    GROUP BY dept_id  
)  
SELECT e.*  
FROM employees e  
JOIN latest_hires l  
ON e.dept_id = l.dept_id  
AND e.hire_date = l.max_hire_date;

查询结果
emp_id dept_id emp_name hire_date
102 1 李四 2024-01-01
103 2 王五 2024-02-15

解释

  • 第一个 CTE latest_hires 计算每个部门的最新入职时间。
  • 通过 JOIN 筛选出最新入职的员工记录。


四、总结

  • CTE 简化复杂查询:将复杂子查询或递归逻辑拆分成易读的步骤,提高代码可维护性。
  • 递归 CTE 是生成层次结构(如树形关系、组织架构)的理想工具。
  • CTE 支持嵌套和多层次查询,可以轻松解决分层汇总、动态累计等问题,提高查询性能和可读性。
相关推荐
熟透的蜗牛3 分钟前
大数据技术(八)—— HBase数据读写流程和Api的使用
大数据·数据库·hbase
PersistJiao6 分钟前
Couchbase 的 OLAP 能力现状以及提升 OLAP 能力的方法
数据库·couchbase
对,就是哥14 分钟前
ABAP弹出对对话框错误信息设计
java·数据库·算法
Minxinbb16 分钟前
MySQL DBA需要掌握的 7 个问题
数据库·mysql·dba
drebander20 分钟前
MySQL 索引优化实战 – 结合 Explain 深度解析慢查询
android·数据库·mysql
_.Switch27 分钟前
FastAPI 响应模型与自定义响应
开发语言·前端·数据库·python·fastapi·命令模式
对,就是哥29 分钟前
ABAP 两个内表不同名称字段赋值的方法
运维·数据库·windows
杰九1 小时前
【全栈】SprintBoot+vue3迷你商城(2)
java·数据库·spring boot·mysql
华年源码1 小时前
基于springboot的课程作业管理系统(源码+数据库+文档)
java·数据库·毕业设计·源码·springboot
L73S371 小时前
栈和队列详解
数据结构·数据库·程序人生·算法·链表·学习方法