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 支持嵌套和多层次查询,可以轻松解决分层汇总、动态累计等问题,提高查询性能和可读性。
相关推荐
蜡笔小炘10 分钟前
LVS -- 利用防火墙标签(FireWall Mark)解决轮询错误
服务器·数据库·lvs
韩立学长13 分钟前
基于Springboot泉州旅游攻略平台d5h5zz02(程序、源码、数据库、调试部署方案及开发环境)系统界面展示及获取方式置于文档末尾,可供参考。
数据库·spring boot·旅游
Re.不晚1 小时前
MySQL进阶之战——索引、事务与锁、高可用架构的三重奏
数据库·mysql·架构
老邓计算机毕设1 小时前
SSM智慧社区信息化服务平台4v5hv(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面
数据库·ssm 框架·智慧社区、·信息化平台
麦聪聊数据1 小时前
为何通用堡垒机无法在数据库运维中实现精准风控?
数据库·sql·安全·低代码·架构
2301_790300961 小时前
Python数据库操作:SQLAlchemy ORM指南
jvm·数据库·python
m0_736919102 小时前
用Pandas处理时间序列数据(Time Series)
jvm·数据库·python
亓才孓2 小时前
[JDBC]PreparedStatement替代Statement
java·数据库
m0_466525292 小时前
绿盟科技风云卫AI安全能力平台成果重磅发布
大数据·数据库·人工智能·安全
爱学习的阿磊3 小时前
使用Fabric自动化你的部署流程
jvm·数据库·python