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 支持嵌套和多层次查询,可以轻松解决分层汇总、动态累计等问题,提高查询性能和可读性。
相关推荐
计算机毕设定制辅导-无忧学长1 小时前
西门子 PLC 与 Modbus 集成:S7-1500 RTU/TCP 配置指南(一)
服务器·数据库·tcp/ip
程序员柳2 小时前
基于微信小程序的校园二手交易平台、微信小程序校园二手商城源代码+数据库+使用说明,layui+微信小程序+Spring Boot
数据库·微信小程序·layui
梦在深巷、2 小时前
MySQL/MariaDB数据库主从复制之基于二进制日志的方式
linux·数据库·mysql·mariadb
IT乌鸦坐飞机2 小时前
ansible部署数据库服务随机启动并创建用户和设置用户有完全权限
数据库·ansible·centos7
IT_10242 小时前
Spring Boot项目开发实战销售管理系统——数据库设计!
java·开发语言·数据库·spring boot·后端·oracle
祁思妙想4 小时前
八股学习(三)---MySQL
数据库·学习·mysql
惊骇世俗王某人4 小时前
1.MySQL之如何定位慢查询
数据库·mysql
程序员张34 小时前
SQL分析与打印-p6spy组件
spring boot·sql·mybatis·mybatisplus·p6spy
秦歌6665 小时前
向量数据库-Milvus快速入门
数据库·milvus
Edingbrugh.南空6 小时前
Flink SQLServer CDC 环境配置与验证
数据库·sqlserver·flink