SQL语句中实现递归查询操作方法

 更新时间:2026年05月22日 09:33:44   作者:rchmin  
这篇文章给大家介绍SQL语句中实现递归查询操作方法,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧

在SQL中实现递归查询操作,通常有两种主要的方法:使用递归公用表表达式(Recursive Common Table Expressions,CTEs)和递归查询函数(例如,在PostgreSQL中使用WITH RECURSIVE,在SQL Server中使用WITH RECURSIVECTE,而在Oracle中使用CONNECT BY)。

数据表定义:

CREATE TABLE employees (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    manager_id INT  -- 指向上级,CEO的manager_id为NULL(或0,通常用NULL表示无上级)
);

初始化数据:

INSERT INTO `employees` (`id`, `name`, `manager_id`) VALUES (101, '马总', NULL);
INSERT INTO `employees` (`id`, `name`, `manager_id`) VALUES (201, '张工', 101);
INSERT INTO `employees` (`id`, `name`, `manager_id`) VALUES (202, '王工', 101);
INSERT INTO `employees` (`id`, `name`, `manager_id`) VALUES (301, '李工', 201);
INSERT INTO `employees` (`id`, `name`, `manager_id`) VALUES (401, '赵工', 301);
INSERT INTO `employees` (`id`, `name`, `manager_id`) VALUES (402, '刘工', 301);

查询需求:

请查询出id=101的人员及其所有的下级信息(包括间接下级),同时标记出下属层级,自身层级设为0;

查询语句(MySQL 8.0+):

要查询 id = 101 的所有下级(包括直接和间接下级),并标记出每个下属所处的层级(1 表示直接下级,2 表示下级的下级,依此类推),可以使用递归公用表表达式(Recursive CTE)。以下是符合要求的 SQL 语句:

WITH RECURSIVE subordinates AS (
    -- 初始查询:找到直接下级(manager_id = 101)
    SELECT 
        id,
        name,
        manager_id,
        0 AS level
    FROM employees
    WHERE id = 101
    UNION ALL
    -- 递归查询:找到下一级下属
    SELECT 
        e.id,
        e.name,
        e.manager_id,
        s.level + 1
    FROM employees e
    INNER JOIN subordinates s ON e.manager_id = s.id
)
SELECT *
FROM subordinates
ORDER BY level, id;

执行结果:

语法解释:

WITH RECURSIVE subordinates AS (...) 是 SQL 中用于定义递归公用表表达式(Recursive Common Table Expression)的语法。下面逐部分解释:

1.WITH关键字

  • 表示定义一个公用表表达式(CTE,Common Table Expression),类似于一个临时的命名结果集,可以在后续的查询中引用。
  • 通常用于简化复杂查询,提高可读性。

2.RECURSIVE关键字

  • 指明该 CTE 是递归的,即它可以在自己的定义中引用自身,从而实现迭代或层次遍历。
  • 大部分主流数据库(如 PostgreSQL、MySQL 8.0+、SQL Server、Oracle)都支持该语法,但 MySQL 中必须明确写出 RECURSIVE,而 SQL Server 中可省略(但需要其他方式表示递归)。

3.subordinates– CTE 名称(自定义)

  • 给这个临时结果集取名为 subordinates,后续的 SELECT 语句就可以像使用普通表一样使用它。

4. 括号内的递归定义

递归 CTE 通常由两部分组成,用 UNION ALL 连接:

(1)锚点成员(非递归部分)

SELECT id, name, manager_id, 1 AS level
FROM employees
WHERE id = 101
  • 这是递归的起点,首先查询出 id = 101 的员工(即 101 自身)。
  • 这里手动标记 level = 0,表示第 0 层级。
  • 锚点成员只执行一次,其结果集作为递归的初始数据。

(2)递归成员(递归部分)

SELECT e.id, e.name, e.manager_id, s.level + 1
FROM employees e
INNER JOIN subordinates s ON e.manager_id = s.id
  • 递归成员会反复执行,直到不再返回新行。
  • 每次迭代中,它只将上一轮 subordinates 结果集中的每一行(作为上级 s)与 employees 表连接,找出这些上级的下级员工(e.manager_id = s.id)。
  • 同时,层级别为 s.level + 1,表示比上一级深一层。
  • 新找到的行被加入 subordinates 结果集,并用于下一次迭代。

(3) 终止条件

  • 当某次迭代没有产生任何新行时,递归自动停止。
  • 要求数据中没有循环引用(例如 A 的上级是 B,B 的上级又是 A),否则可能导致无限递归。大多数数据库默认设置了递归深度限制(如 MySQL 的 cte_max_recursion_depth)。

5. 最终引用

定义完 subordinates 后,外层的 SELECT * FROM subordinates 将返回所有递归收集到的行。

示例执行流程

假设 employees 表有数据:

  • id=101 管理 201,202
  • 201 管理 301
  • 301 管理 401,402

执行过程:

  • 锚点:找到 201、202,level=1。
  • subordinates 当前有 (201, ..., 1), (202, ..., 1)。
  • 第一次递归:以 201、202 为上级找下级 → 找到 301(上级 201),level=2。
  • subordinates 新增 (301, ..., 2)。
  • 第二次递归:以 301 为上级找下级 → 找到 401,402,level=3。
  • subordinates 新增 (401, ..., 3),(402, ..., 3)。
  • 第三次递归:以 401、402 为上级找下级 → 无结果,终止。
  • 最终输出所有行。

适用场景

  • 组织架构(上级-下级)
  • 物料清单(BOM)
  • 树形结构遍历(评论回复、分类层级)
  • 图或路径查询

WITH RECURSIVE 是处理此类分层或递归查询的标准 SQL 方法,比使用游标或多次自连接更加简洁高效。

到此这篇关于SQL语句中如何实现递归查询操作的文章就介绍到这了,更多相关SQL递归查询内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SQL server数据库declare和set用法技巧小结

    SQL server数据库declare和set用法技巧小结

    这篇文章主要给大家介绍了关于SQL server数据库declare和set用法技巧的相关资料,在SQL Server中,DECLARE用于声明变量和存储过程中的参数,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-08-08
  • Android实现矩形区域截屏的方法

    Android实现矩形区域截屏的方法

    对屏幕进行截屏并裁剪有两种方式:早截图和晚截图,对于早截图和晚截图的概念大家通过本文详解学习。本文重点给大家介绍android实现矩形区域截屏的方法,需要的朋友参考下
    2017-01-01
  • PL/SQL DEVELOPER 使用的一些技巧

    PL/SQL DEVELOPER 使用的一些技巧

    了解一点编程的常识的人都知道,编码风格很重要。在阅读代码方面,保持一致的编码风格,阅读起来比较容易;大家都应该养成一种自己的编码习惯,并保持下去。
    2013-04-04
  • 远程登陆SQL Server 2014数据库的方法

    远程登陆SQL Server 2014数据库的方法

    这篇文章主要为大家详细介绍了远程登陆SQL Server 2014数据库的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-08-08
  • SQL中redo log 刷⼊磁盘的常见方法

    SQL中redo log 刷⼊磁盘的常见方法

    本文主要介绍了SQL中redo log 刷⼊磁盘的常见方法,将redo log刷入磁盘的方法确保了数据的持久性和一致性,下面就来具体介绍一下,感兴趣的可以了解一下
    2025-04-04
  • SQL NOT NULL约束的概念、用法详解

    SQL NOT NULL约束的概念、用法详解

    NOT NULL约束是SQL数据库中一种重要的数据完整性约束,用于确保数据库表中的字段不会存储任何NULL值,本文将详细介绍NOT NULL约束的概念、用法以及它在数据库设计中的重要性,感兴趣的朋友跟随小编一起看看吧
    2026-01-01
  • SQL MID() 函数详解与使用指南

    SQL MID() 函数详解与使用指南

    MID()函数是SQL中处理字符串的常用函数之一,本文就来了解一下SQL MID()函数的具体使用,具有一定的参考价值,感兴趣的可以了解一下
    2025-10-10
  • AspNetPager分页控件 存储过程

    AspNetPager分页控件 存储过程

    我用AspNetPager分页控件,写的存储过程
    2009-08-08
  • SQL Server事务日志已满的三种解决方案

    SQL Server事务日志已满的三种解决方案

    我们安装数据库后,系统会默认把数据库文件和数据库日志文件最大设为500MB,当然你中途可以更改这个限制,当日志文件接近最大值时,继续使用数据库会提示:事务日志已满,本文给出了三种解决方案,需要的朋友可以参考下
    2023-11-11
  • MSSQL批量插入数据优化详细

    MSSQL批量插入数据优化详细

    这篇文章主要为大家分享一下批量插入数据的方法,有时候我们需要插入大量的数据那么就需要优惠了,要不根本受不了
    2017-07-07

最新评论