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 my.ini 配置文件详解

    Mysql my.ini 配置文件详解

    Mysql my.ini 配置文件详解
    2009-06-06
  • mysql启动提示:错误2系统找不到指定文件的解决方案

    mysql启动提示:错误2系统找不到指定文件的解决方案

    这篇文章主要给大家介绍了mysql启动提示:错误2系统找不到指定文件的解决方案,文中通过图文结合的方式给大家讲解的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
    2024-02-02
  • MySQL中any、some和all的用法实例

    MySQL中any、some和all的用法实例

    最近一直在练习MYSQL的多表查询,基本上每个查询语句我都会写至少两次,下面这篇文章主要给大家介绍了关于MySQL中any、some和all用法的相关资料,需要的朋友可以参考下
    2022-11-11
  • DB为何大量出现select @@session.tx_read_only 详解

    DB为何大量出现select @@session.tx_read_only 详解

    这篇文章主要给大家介绍了关于DB为何大量出现select @@session.tx_read_only 的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
    2018-04-04
  • mysql中的“money”类型说明

    mysql中的“money”类型说明

    mysql没有money类型 sql server才有money类型
    2008-06-06
  • 在MySQL中使用通配符时应该注意的问题

    在MySQL中使用通配符时应该注意的问题

    这篇文章主要介绍了在MySQL中使用通配符时应该注意的问题,主要是下划线的使用容易引起的错误,需要的朋友可以参考下
    2015-05-05
  • mysql数据库连接失败常见问题小结

    mysql数据库连接失败常见问题小结

    你有没有碰到过mysql数据库连接不上的问题呢?很多的小伙伴表示,经常会时不时的出现这些问题,下面这篇文章主要给大家介绍了关于mysql数据库连接失败常见问题的相关资料,需要的朋友可以参考下
    2023-06-06
  • mysql 批量给数据表和字段添加注释

    mysql 批量给数据表和字段添加注释

    在MySQL中,添加注释可以帮助人们更好地理解和管理数据库,本文就介绍了mysql 批量给数据表和字段添加注释,感兴趣的可以了解一下
    2023-08-08
  • mysql日期函数TO_DAYS()函数的详细讲解

    mysql日期函数TO_DAYS()函数的详细讲解

    在SQL中我们经常需要根据时间字段查询数据,今天用到一个好用的时间字段,用来查询一整天的数据,下面这篇文章主要给大家介绍了关于mysql日期函数TO_DAYS()函数的相关资料,需要的朋友可以参考下
    2022-08-08
  • MySQL动态SQL拼接实例详解

    MySQL动态SQL拼接实例详解

    动态SQL呢?首先是SQL语句,是根据条件来拼接SQL,下面这篇文章主要给大家介绍了关于MySQL动态SQL拼接的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-12-12

最新评论