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 支持嵌套和多层次查询,可以轻松解决分层汇总、动态累计等问题,提高查询性能和可读性。
相关推荐
2401_887724501 分钟前
SQL注入的安全架构设计_将数据库置于内网隔离区
jvm·数据库·python
m0_678485452 分钟前
如何配置文件描述符限制_limits.conf中Oracle用户配置
jvm·数据库·python
我科绝伦(Huanhuan Zhou)3 分钟前
Oracle BBED 工具部署全流程:Linux 64位环境实操指南
linux·数据库·oracle
2401_835956814 分钟前
HTML5中Canvas局部刷新区域重绘的算法优化
jvm·数据库·python
marsh02065 分钟前
34 openclaw事件溯源:实现可追溯的业务流程
数据库·ai·编程·技术
coderlin_5 分钟前
LangGraph项目二 同步数据仓库信息到元数据库并且建立向量索引
数据库·数据仓库
weixin_408717777 分钟前
如何导入带系统变量修改的SQL_确保SUPER权限并规避只读变量报错
jvm·数据库·python
m0_678485458 分钟前
c++怎么编写多线程安全的跨平台文件日志库_无锁队列与异步IO【附源码】
jvm·数据库·python
m0_746752309 分钟前
PHP源码运行时风扇狂转怎么办_硬件温控调优方法【说明】
jvm·数据库·python
liyi_hz200810 分钟前
O2OA V10 升级说明(二)内容管理:更安全、更融合、更适配移动办公
java·前端·数据库