SQL SERVER递归查询的实现

 更新时间:2024年01月03日 11:19:07   作者:MoFe1  
本文主要介绍了SQL SERVER递归查询的实现,递归查询是通过CTE来实现,具有一定的参考价值,感兴趣的可以了解一下

 有示例数据,表名为SYS_Department

iddepartmentNameparentIdremarkisEnablestaffId
2总经理1总经理1
3账务部2账务部11006
4技术部2技术部11004
9产品部2产品部11005
10市场部2市场部1
11人事部2人事部11013
5测试部4测试部11002
6开发部4开发部11003
7设计部4设计部1
8物联部4物联部1
12JAVA一部6JAVA一部11009
13JAVA二部6JAVA二部1
14.NET部6.NET部11008
15前端部6前端部1

递归查询原理

SQL Server中的递归查询是通过CTE(表表达式)来实现。至少包含两个查询,第一个查询为定点成员,定点成员只是一个返回有效表的查询,用于递归的基础或定位点;第二个查询被称为递归成员,使该查询称为递归成员的是对CTE名称的递归引用是触发。在逻辑上可以将CTE名称的内部应用理解为前一个查询的结果集。

递归查询语法

with 子查询名称 查询字段列表 as --查询字段列表输入格式为([查询字段名1],[查询字段名2],...),也可用*代替,需要注意的是此处的查询字段列表中的字段与下方内容中定点成员与递归成员查询字段列表内容需一致
( 
--定点成员
select 查询字段列表 from 查询表名 where 查询条件 
union all 
--递归成员
select 查询字段列表 from 查询表名 a inner join 子查询名称 on 递归条件 ) 
select 显示字段名 from 子查询名称

已示例数据为例

--查询1
--通过根节点向下查找该根节点下的子节点
with temp([id],[departmentName],[parentId])  as --temp([id],[departmentName])指定temp结果集中的列,如设置需包含联表条件
( select [id],[departmentName],[parentId] from SYS_Department where id = 2
union all select a.[id],a.[departmentName],a.[parentId] from SYS_Department a inner join temp on a.[parentId] = temp.[id] ) 
select  [id],[departmentName] from temp

--查询2
--通过子节点向上查找该子节点的根节点
with temp([id],[departmentName],[parentId])  as 
( select [id],[departmentName],[parentId] from SYS_Department where id = 2
union all select a.[id],a.[departmentName],a.[parentId] from SYS_Department a inner join temp on
--调换查询字段
a.[id] = temp.[parentId] ) 
select  [id],[departmentName] from temp

查询2查询结果

mysql示例 使用recursive关键字

--Mysql 查询时联表条件与SQL SERVER相反
--父查子
with recursive temp(Id,DepartmentName,ParentId) as 
(select Id,DepartmentName,ParentId from SYS_Department  where id = 2
union all 
select a.Id,a.DepartmentName,a.ParentId from SYS_Department a inner join temp on a.ParentId  = temp.Id)
select * from temp

--子查父
with recursive temp(Id,DepartmentName,ParentId) as 
(select Id,DepartmentName,ParentId from SYS_Department  where id = 2
union all 
select a.Id,a.DepartmentName,a.ParentId from SYS_Department a inner join temp on a.Id = temp.ParentId )
select * from temp

不指定查询字段列表

--查询1
--不指定子查询查询字段列表
with temp as 
(
--查询表中所有字段 
select * from SYS_Department where id = 2
union all 
--查询主表中所有字段(根据UNION ALL语法需与定点成员查询字段保持一致)
select a.* from SYS_Department a inner join temp on a.[parentId] = temp.[id] ) 
--显示表中所有字段
select * from temp

--查询2
--不指定子查询查询字段列表
with temp as 
(
--查询表中所有字段 
select * from SYS_Department where id = 2
union all 
--查询主表中所有字段(根据UNION ALL语法需与定点成员查询字段保持一致)
select a.* from SYS_Department a inner join temp on a.[parentId] = temp.[id] ) 
--显示表中id字段
select id from temp

查询结果1

查询结果2

 总结:

以树的概念去理解查询原理可能相对比较容易一些,以下是以结果反推的个人理解:

关键字:

定点成员(示例语句中:select * from SYS_Department where id = 2)

递归成员(示例语句中:select a.* from SYS_Department a inner join temp on a.[parentId] = temp.[id])

拼接(使用UNION ALL)

SQL递归查询是以定点成员为查询起始点(即语句中的select * from SYS_Department where id = 2),第一次查询时取到定点成员的子节点(即示例数据中parentid=2的数据,可以将查询起始点理解为树的根节点),通过特定的顺序遍历取到的子节点(遍历顺序经测试为倒序遍历,即先遍历id=4的数据,再遍历id=3的数据),当该子节点下存在数据时(即已select a.* from SYS_Department a inner join temp on a.[parentId] = temp.[id]的查询结果不为NULL时)显示数据并继续遍历该节点,直至查询导的结果为空或达到最大的迭代次数(默认为100),最终将所有节点遍历完成并将遍历的结果以UNION ALL语句拼接输出结果集。

以示例数据为例,反推的查询流程以及数据如图所示:

 1.第一次递归时(目前无法确定开始执行的顺序是先执行定点成员语句后递归还是获取到子节点后递归,猜测顺序为执行完定点成员SQL后进行第一次递归)获取拼接下图中

2.递归遍历通过定点成员获取到的子节点,先遍历id=11的节点,但该节点下获取的数据为空所以不拼接任何数据,id=10和9的同理,当遍历到id为4的节点时,获取拼接下图数据

 3.递归遍历上图中获取到的节点,先遍历id=8的节点,但该节点下获取的数据为空所以不拼接任何数据,id=7和5的同理,当遍历到id为6的节点时,获取拼接下图数据

 4.递归遍历上图中获取到的节点,先遍历id=15的节点,但该节点下获取的数据为空所以不拼接任何数据,id=14,13,12的节点同理

5.此时以id=4的节点为根节点的所有节点已遍历完成,继续递归遍历通过定点成员获取到的子节点,即遍历id=3的节点,但该节点下获取的数据为空所以不拼接任何数据,最终显示结果集如下图所示

 原文参考:

WITH common_table_expression (Transact-SQL) | Microsoft Docs

Recursive Queries Using Common Table Expressions | Microsoft Docs

思路借鉴:SQL中的递归的用法_SQL数据库开发的博客-CSDN博客

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

相关文章

  • 关于MySQL查询语句的优化详解

    关于MySQL查询语句的优化详解

    这篇文章主要介绍了MySQL查询语句的优化方法,分别介绍了子查询优化,分页查询优化以及排序查询优化,对学习有一定的帮助,需要的小伙伴可以参考一下
    2023-04-04
  • Mysql之如何创建函数问题

    Mysql之如何创建函数问题

    这篇文章主要介绍了Mysql之如何创建函数问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03
  • Mysql简易索引方案讲解

    Mysql简易索引方案讲解

    这篇文章主要为大家介绍了Mysql索引如何实现更加简易的查找方案,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-05-05
  • MySQL有5种索引类型及其特点详解

    MySQL有5种索引类型及其特点详解

    MySQL中的索引类型多种多样,每种索引类型都有其特定的使用场景和优势,这篇文章主要介绍了MySQL有5种索引类型及其特点的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2026-01-01
  • Navicat for Mysql 字段注释中文乱码问题及解决

    Navicat for Mysql 字段注释中文乱码问题及解决

    这篇文章主要介绍了Navicat for Mysql 字段注释中文乱码问题及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-09-09
  • mysql5.7安装教程(windows)

    mysql5.7安装教程(windows)

    这篇文章主要为大家详细介绍了windows下mysql5.7安装教程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-12-12
  • 从0到1学会MySQL单表查询

    从0到1学会MySQL单表查询

    这篇文章主要给大家介绍了关于如何从0到1学会MySQL单表查询的相关资料,单表查询是指从一张表数据中查询所需的数据,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2023-11-11
  • MySQL多条件查询的实现示例

    MySQL多条件查询的实现示例

    本文主要介绍了MySQL多条件查询的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-05-05
  • mysql 8.0.12 winx64下载安装教程

    mysql 8.0.12 winx64下载安装教程

    这篇文章主要为大家详细介绍了mysql 8.0.12 winx64下载安装教程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-09-09
  • mysql大批量插入数据的4种方法示例

    mysql大批量插入数据的4种方法示例

    这篇文章主要给大家介绍了关于mysql大批量插入数据的4种方法,文中通过示例代码介绍的非常详细,对大家学习或者使用mysql具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-06-06

最新评论