在TSQL脚本中,也能实现递归查询,SQL Server提供CTE(Common Table Expression),只需要编写少量的代码,就能实现递归查询,本文详细介绍CTE递归调用的特性和使用示例,递归查询主要用于层次结构的查询,从叶级(Leaf Level)向顶层(Root Level)查询,或从顶层向叶级查询,或递归的路径(Path)。

一,递归查询原理

CTE的递归查询必须满足三个条件:初始条件,递归调用表达式,终止条件,CTE 递归查询的伪代码如下:

WITH cte_name ( column_name [,...n] )
AS ( --Anchor member is defined CTE_query_definition UNION ALL --Recursive member is defined referencing cte_name CTE_query_definition ) -- Statement using the CTE SELECT * FROM cte_name

1,递归查询至少包含两个子查询:

  • 第一个子查询称作定点(Anchor)子查询:定点查询只是一个返回有效表的查询,用于设置递归的初始值;
  • 第二个子查询称作递归子查询:该子查询调用CTE名称,触发递归查询,实际上是递归子查询调用递归子查询;
  • 两个子查询使用union all,求并集;

2,CTE的递归终止条件

递归查询没有显式的递归终止条件,只有当递归子查询返回空结果集(没有数据行返回)或是超出了递归次数的最大限制时,才停止递归。

默认的递归查询次数是100,可以使用查询提示(hint):MAXRECURSION 控制递归的最大次数:OPTION( MAXRECURSION 16);如果允许无限制的递归次数,使用查询提示:option(maxrecursion 0);当递归查询达到指定或默认的 MAXRECURSION 数量限制时,SQL Server将结束查询并返回错误,如下:

The statement terminated. The maximum recursion 10 has been exhausted before statement completion.

事务执行失败,该事务包含的所有操作都被回滚。在产品环境中,慎用maxrecursion 查询提示,推荐通过 where 条件限制递归的次数。

3,递归步骤

step1:定点子查询设置CTE的初始值,即CTE的初始值Set0;

递归调用的子查询过程:递归子查询调用递归子查询;

step2:递归子查询第一次调用CTE名称,CTE名称是指CTE的初始值Set0,第一次执行递归子查询之后,CTE名称是指结果集Set1;

step3:递归子查询第二次调用CTE名称,CTE名称是指Set1,第二次执行递归子查询之后,CTE名称是指结果集Set2;

step4:在第N次执行递归子查询时,CTE名称是指Set(N-1),递归子查询都引用前一个递归子查询的结果集;

Step5:如果递归子查询返回空数据行,或超出递归次数的最大限制,停止递归;

二,递归查询示例(员工职称)

1,创建测试数据

ManagerID是UserID的父节点,这是一个非常简单的层次结构模型。

use tempdb
go create table dbo.dt_user ( UserID int, ManagerID int, Name Nvarchar(10) ) insert into dbo.dt_user select 1,-1,N'Boss' union all select 11,1,N'A1' union all select 12,1,N'A2' union all select 13,1,N'A3' union all select 111,11,N'B1' union all select 112,11,N'B2' union all select 121,12,N'C1'

2,查询每个User的的直接上级Manager

;with cte as
(
select UserID,ManagerID,name,name as ManagerName from dbo.dt_user where ManagerID=-1 union all select c.UserID,c.ManagerID,c.Name,p.name as ManagerName from cte P inner join dbo.dt_user c on p.UserID=c.ManagerID ) select UserID,ManagerID,Name,ManagerName from cte order by UserID

step1:查询ManagerID=-1,作为root node,这是递归查询的起始点。

step2:迭代公式是 union all 下面的查询语句。在查询语句中调用中cte,而查询语句就是cte的组成部分,即 “自己调用自己”,这就是递归的真谛所在。

所谓迭代,是指每一次递归都要调用上一次查询的结果集,Union ALL是指每次都把结果集并在一起。

step3-N,迭代公式利用上一次查询返回的结果集执行特定的查询,直到CTE返回null 或达到最大的迭代次数,默认值是32。最终的结果集是迭代公式返回的各个结果集的并集,求并集是由Union All 子句定义的,并且只能使用Union ALL。

3,查询路径,在层次结构中查询子节点到父节点的path

;with cte as
(
select UserID,ManagerID,name,cast(name as nvarchar(max)) as ReportPath from dbo.dt_user where ManagerID=-1 union all select c.UserID,c.ManagerID,c.Name,c.name+'->'+p.ReportPath as ReportPath from cte P inner join dbo.dt_user c on p.UserID=c.ManagerID ) select UserID,ManagerID,Name,ReportPath from cte order by UserID

查询结果如下截图:

三,递归查询示例(行政区划)

1,需求模拟

在TSQL中实现层次结构,例如有这样一种数据结构,省,市,县,乡,村,如何使用一张表表示这种数据结构,并且允许是不对称的,例如,上海市是个直辖市,没有省份。

create table dbo.hierarchy
(
ID  int not null primary key, --type int not null, ParentID int not null, name varchar(100) not null )

type表示类型,可以设置:省,Type是1;市,type是2,以此类推。

ParentID标识的是父级ID,例如信阳市的ParentID是河南省的ID。

2,插入测试数据

测试数据格式说明了归属关系,博主懒,去掉type字段。

insert into dbo.hierarchy
values(1,0,'河南省') ,(2,1,'信阳市'),(3,2,'淮滨县'),(4,3,'芦集乡'),(12,3,'邓湾乡'),(13,3,'台头乡'),(14,3,'谷堆乡') ,(8,2,'固始县'),(9,8,'李店乡') ,(10,2,'息县'),(11,10,'关店乡') ,(5,1,'安阳市'),(6,5,'滑县'),(7,6,'老庙乡') ,(15,1,'南阳市'),(16,15,'方城县') ,(17,1,'驻马店市'),(18,17,'正阳县') select * from dbo.hierarchy order by ParentID

3,实现由父级向子级的查询

由于实际的数据可能有很多,所以,要想获取河南省下的所有市,县,乡,村等信息,必须使用递归查询

;with cte(Id,ParentID,Name) as
(
select *
from dbo.hierarchy where id=1 union all select h.* from dbo.hierarchy h inner join cte c on h.ParentID=c.id --where c.id!=h.ID ) select * from cte order by ParentID

如果要查看向内递归到多少level,可以使用派生列,level=0是省level,level=1是市level,依次类推。

;with cte(Id,ParentID,Name,Level) as
(
select ID,ParentID,Name,0 as Level from dbo.hierarchy where id=1 union all select h.ID,h.ParentID,h.Name,c.Level+1 as Level from dbo.hierarchy h inner join cte c on h.ParentID=c.id --where c.id!=h.ID ) select * from cte order by ParentID

查询结果如图:

4,由子级向父级的递归查询

;with cte as
(
select ID,ParentID,name
from dbo.hierarchy where id=4 --芦集乡的ID union all select h.ID,h.ParentID,h.name from dbo.hierarchy h inner join cte c on h.id=c.ParentID ) select ID,ParentID,name from cte order by ParentID

查询结果如图:

http://blog.csdn.net/3150379/article/details/54865603

转载于:https://www.cnblogs.com/LCX/p/8367472.html

SQL Server CTE 递归查询全解相关推荐

  1. VB访问SQL Server数据库技术全揭密

    VB访问SQL Server数据库技术全揭密 2006-08-03 05:00作者:出处:电子技术责任编辑:方舟 摘 要: 本文讨论了Visual Basic应用程序访问SQL Server数据库的几 ...

  2. SQL Server:触发器详解

    SQL Server:触发器详解 1. 概述 2. 触发器的分类 3. Inserted和Deleted表 4. 触发器的执行过程 5. 创建触发器 6. 修改触发器: 7. 删除触发器: 8. 查看 ...

  3. MS SQL Server 数据库连接字符串详解

    MS SQL Server 数据库连接字符串详解 问题 : 超时时间已到.在从池中获取连接之前超时时间已过.出现这种情况可能是因为所有池连接都已被使用并已达到最大池大小. 解决办法 1. 在代码里面 ...

  4. mysql coalesce函数用法,SQL Server COALESCE函数详解及实例

    SQL Server COALESCE函数详解 很多人知道ISNULL函数,但是很少人知道Coalesce函数,人们会无意中使用到Coalesce函数,并且发现它比ISNULL更加强大,其实到目前为止 ...

  5. mysql cte递归_CTE 递归查询全解

    TSQL脚本能实现递归查询,用户使用共用表表达式 CTE(Common Table Expression),只需要编写少量的代码,就能实现递归查询.本文详细介绍CTE递归调用的特性和使用示例,递归查询 ...

  6. 【SQL SERVER】递归查询

    有示例数据,表名为SYS_Department id departmentName parentId remark isEnable staffId 2 总经理 1 总经理 1 3 账务部 2 账务部 ...

  7. SQL Server存储过程里全库查找引用的数据库对象(表、存储过程等)

    SQL Server存储过程全库匹配数据库对象(表.存储过程等) 简介 可以通过自定义存储过程sp_eachdb来遍历每个数据库然后结合sys.objects 关联sys.sql_modules后的d ...

  8. sql server 存储过程的详解

    SqlServer存储过程详解 1.创建存储过程的基本语法模板: if (exists (select * from sys.objects where name = 'pro_name'))drop ...

  9. sql server的搜索_在SQL Server中进行全文本搜索

    sql server的搜索 介绍 (Introduction) In most cases, we will use clustered and non-clustered indexes to he ...

最新文章

  1. 炸裂!VSCode 摸鱼神器!!!
  2. nodejs-模块系统
  3. 【科普】从HTTP到HTTP/3的发展简史
  4. 【赠书】快速入门自动机器学习!自动机器学习(AutoML):方法、系统与挑战 图书赠送!...
  5. NOV. 2nd, 减肥第三天
  6. nmap扫描局域网存活主机_安全工程师都在用的网络扫描软件,巧用ARP协议发现主机。第二节...
  7. Pwn环境配置(三)——ubuntu环境搭建(新)
  8. python如何绘制曲线图_python pandas plot画折线图如何显示x轴的值?
  9. linux一台机器如何安装两个mysql,在一台linux机器上启动两个mysql实例
  10. discuz仿手游控游戏论坛商业版网站模板
  11. 记住密码 的 简要概述_密码错误的简要历史
  12. mysql索引 实验_“索引”实验小例
  13. 数据结构二叉树线索化
  14. 简述导线平差计算的五个步骤_RTK技术导线测量和全站仪导线测量有什么区别?...
  15. openwrt nas_NAS里整个软路由
  16. 《C语言编程初学者指南》一导读
  17. 对于拼接进去的html原来绑定的jq事件失效
  18. 十大机器学习算法(一)
  19. 人工智能技术的发展促进城市大脑预演数字化城市未来
  20. 《别做正常的傻瓜》1——结果偏见

热门文章

  1. Boost笔记--Thread--Ubuntu上初次使用时遇到的问题
  2. Windows环境下多线程编程原理与应用读书笔记(8)————信号量及其应用
  3. 2013腾讯编程马拉松初赛第二场(3月22日) 小Q系列故事——为什么时光不能倒流 ---好水!!...
  4. 用C#实现对Oracle 存储过程/函数/包的调试(附源代码)
  5. php网页,想弹出对话框, 消息框 简单代码
  6. CodeProject每日精选: Progress controls 进度条
  7. 前端javascript经典面试题集合(2020年最新)
  8. TensorFlow2.0(九)--Keras实现基础卷积神经网络
  9. Dart 7-Day
  10. Modularity(模块化-UMD通用模式)