CTE递归原理:
递归CTE是由两个最小查询构建的.第一个是定位成员(Anchor Member,AM),它是一个非递归查询,第二个是递归成员(Recursive Member,RM),它是递归查询.在CTE括号中(AS 子句之后),定义独立查询或引用回相同CTE的查询,AM与RM由UNION ALL语句分隔.AM紧被调用一次,RM将被重复调用,直到查询不在返回数据行为止.可以使用UNION或UNION ALL运算符彼此追加多个AM,具体取决于是否希望删除重复数据(必须使用UNION ALL运算符来追加递归成员).语法如下:
–需要查询字段集合,也是查询结果的字段集合 WITH SimpleRecursive(filed names) AS ( –查询定位成员表 <SELECT Statement for the Anchor Member> UNION ALL –查询递归成员表 <SELECT Statement for the Recursive Member> ) SELECT * FROM SimpleRecursive |
实例:我们将创建一个员工表和一个名为ReportsTo的自引用字段,其引用回Emloyee_ID,然后编写一个查询,其返回像Stephen(Employee_ID=2)报告的所有员工以及向Stephen的下属报告的所有员工.
代码清单: –创建表 CREATE TABLE Employee_Tree ( Employee_NM NVARCHAR(50) , Employee_ID INT PRIMARY KEY , ReportsTo INT ) INSERT INTO Employee_Tree VALUES ( ‘Richard’, 1, NULL ) INSERT INTO Employee_Tree VALUES ( ‘Stephen’, 2, 1 ) INSERT INTO Employee_Tree VALUES ( ‘Clemens’, 3, 2 ) INSERT INTO Employee_Tree VALUES ( ‘Malek’, 4, 2 ) INSERT INTO Employee_Tree VALUES ( ‘Goksin’, 5, 4 ) INSERT INTO Employee_Tree VALUES ( ‘Kimberly’, 6, 1 ) INSERT INTO Employee_Tree VALUES ( ‘Ramesh’, 7, 5 ) –创建递归查询 WITH SimpleRecursive ( Employee_NM, Employee_ID, ReportsTo ) AS ( SELECT Employee_NM , Employee_ID , ReportsTo FROM Employee_Tree WHERE Employee_ID = 2 UNION ALL SELECT p.Employee_NM , p.Employee_ID , p.ReportsTo FROM Employee_Tree p INNER JOIN SimpleRecursive A ON A.Employee_ID = p.ReportsTo ) SELECT sr.Employee_ID AS empid , sr.Employee_NM AS Emp , et.Employee_NM AS Boss FROM SimpleRecursive sr INNER JOIN Employee_Tree et ON sr.ReportsTo = et.Employee_ID |
查询结果:
递归过程开始于Employee_ID=2的位置(定义成员或第一个SELECT).它获取该记录,并使用递归递归成员(UNION ALL之后的SELECT)获取所有向Stephen报告的记录以及该记录的子记录.(Goksin向Malek报告,Malek向Stephen报告).每一个后续递归都尝试找到更多的子记录.它们以先前递归已经找到的员工作为父记录.最终该递归不返回结果,这是导致递归停止的原因(为什么没有返回Kimberly的原因).如果该定位成员被改变成Employee_ID=1,则Kimberly也将在结果中被返回.
根据设计,递归成员将一直查找子记录,并可以无限循环.如果您怀疑将会进行许多循环,并希望限制递归调用次数,可以使用OPTION子句在外部查询的后面指定MAXRECURSION选项.
OPTION(MAXRECURSION 25)
这一选项将使sql server2005在cte出现指定限制时产生一条错误.默认情况下,限制为100(即省略该选项时).要不想指定选项.必须将MAXRECURSION设为0.
代码清单: WITH SimpleRecursive ( Employee_NM, Employee_ID, ReportsTo ) AS ( SELECT Employee_NM , Employee_ID , ReportsTo FROM Employee_Tree WHERE Employee_ID = 2 UNION ALL SELECT p.Employee_NM , p.Employee_ID , p.ReportsTo FROM Employee_Tree p INNER JOIN SimpleRecursive A ON A.Employee_ID = p.ReportsTo ) SELECT sr.Employee_ID AS empid , sr.Employee_NM AS Emp , et.Employee_NM AS Boss FROM SimpleRecursive sr INNER JOIN Employee_Tree et ON sr.ReportsTo = et.Employee_ID OPTION(MAXRECURSION 2) |
结果如下:
还会看到以下错误:
消息 530,级别 16,状态 1,第 1 行
语句被终止。完成执行语句前已用完最大递归 2。
一种可以避免出现此异常的方法是使用一个所产生的列来跟踪所在的级别,并包含在WHERE子句中,而不是MAXRECURSION.以下结果与上一示例相同,但不产生错误.
代码清单: WITH SimpleRecursive ( Employee_NM, Employee_ID, ReportsTo ,Sublevel) AS ( SELECT Employee_NM , Employee_ID , ReportsTo, 0 FROM Employee_Tree WHERE Employee_ID = 2 UNION ALL SELECT p.Employee_NM , p.Employee_ID , p.ReportsTo, Sublevel + 1 FROM Employee_Tree p INNER JOIN SimpleRecursive A ON A.Employee_ID = p.ReportsTo ) SELECT sr.Employee_ID AS empid , sr.Employee_NM AS Emp , et.Employee_NM AS Boss FROM SimpleRecursive sr INNER JOIN Employee_Tree et ON sr.ReportsTo = et.Employee_ID WHERE Sublevel <=2 |
我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。
我原创,你原创,我们的内容世界才会更加精彩!
【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】
微信公众号
TechTarget
官方微博
TechTarget中国
作者
相关推荐
-
云端SQL Server高可用性最佳做法
与内部部署相比,在云端运行SQL Server可为数据库软件用户提供更多的灵活性和可扩展性,也可能更省钱。但云 […]
-
绘制数据关系图的利器:SQL Server 图像数据库工具
SQL Server 2017新增了图形数据库功能,你可以使用图结构来表示不同数据元素之间的关系。
-
如何在Azure部署时选择合适的SQL Server?
想要在Azure上运行SQL Server,企业一般会面临两种选择:在Azure虚拟机上安装SQL Server或使用Azure SQL Database。
-
Linux支持的引入 推动了SQL Server 2016集成服务的发展
随着SQL Server的不断发展,集成服务也在发生相应的变化。在最新的SSIS更新中,增加Linux支持和SQL Server 2016升级向导。