CTE递归查询

--导入数据
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'
--CTE的简单例子
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

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

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

2.CTE的递归终止条件

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

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:如果递归子查询返回空数据行,或超出递归次数的最大限制,停止递归;

--查询所有子节点
WITH FCTE AS
(
    SELECT ContentId,FatherContentId,0 as Level FROM ProductSeries_Content AS PSC
    WHERE FatherContentId = 1
    UNION ALL
    SELECT b.ContentId,b.FatherContentId,a.Level+1 as Level FROM FCTE AS a
    INNER JOIN ProductSeries_Content AS b
    ON a.ContentId = b.FatherContentId
)
SELECT * FROM FCTE 

--查询所有父节点
WITH TCTE AS
(
    SELECT ContentId,FatherContentId FROM ProductSeries_Content AS PSC
    WHERE ContentId = 260
    UNION ALL
    SELECT b.ContentId,b.FatherContentId FROM TCTE AS a
    INNER JOIN ProductSeries_Content AS b
    ON a.FatherContentId = b.ContentId
)
SELECT * FROM TCTE 


--补充2点
--The statement terminated. The maximum recursion 100 has been exhausted before statement completion.
--递归次数超过100次,要设置递归次数限制
OPTION(MAXRECURSION 0)
--注意!注意!注意! ContentId的值不能等于FatherContentId,这样数据会无限递归

 

原文地址:https://www.cnblogs.com/lgxlsm/p/7488659.html