SQL递归CTE:查找按属性链接的对象

时间:2017-02-08 16:51:19

标签: sql-server sql-server-2008 tsql common-table-expression recursive-cte

我只是想了解CTE和递归来解决我之前使用游标的问题。

create table ##ACC (
AccNo int,
Property char
)

Insert into ##ACC 
VALUES (1,'A'),(1,'B'),(2,'A'),(2,'C'),(3,'C'),(4,'D')

我想要获得的是获得所有AccNo的列表,以及所有与通过Property相关的AccNo。所以我的预期结果是

PrimaryAccNo | LinkedAccNo
1 | 1
1 | 2
1 | 3
2 | 1
2 | 2
2 | 3
3 | 1
3 | 2
3 | 3
4 | 4

我尝试了以下代码和变体,但我得到4个结果(PrimaryAccNo = LinkedAccNo),或者我达到了100次递归。

WITH Groups(PrimaryAccNo, LinkedAccNo)
AS
(
Select distinct AccNo, AccNo from ##ACC

UNION ALL
Select g.PrimaryAccNo, p.AccNo from
##ACC p inner join Groups g on p.AccNo=g.LinkedAccNo
inner join ##ACC pp on p.Property=pp.Property
where p.AccNo<> pp.AccNo
)
Select PrimaryAccNo,LinkedAccNo 
from Groups

我做错了什么?

1 个答案:

答案 0 :(得分:0)

您正在进入由数据中的周期引起的无限循环,例如:1&gt; 2&gt; 3> 2&gt; ......解决方案是跟踪已经消费的行#34;由于CTE的限制,这必须通过在每个CTE行中包括历史记录来完成,例如,通过组装后面的路径到达每一行。您可以取消评估最终, Path上的select,看看发生了什么。

-- Sample data.
declare @ACC as Table ( AccNo Int, Property Char );
insert into @ACC values
  ( 1, 'A' ), ( 1, 'B' ), ( 2, 'A' ), ( 2, 'C' ), ( 3, 'C' ), ( 4, 'D' );
select * from @ACC;

-- Recursive CTE.
with Groups as (
  select distinct AccNo, AccNo as LinkedAccNo,
    Cast( '|' + Cast( AccNo as VarChar(10) ) + '|' as VarChar(1024) ) as Path
    from @ACC
  union all
  select G.AccNo, A.AccNo, Cast( Path + Cast( A.AccNo as VarChar(10) ) + '|' as VarChar(1024) )
    from Groups as G inner join -- Take the latest round of new rows ...
      @ACC as AP on AP.AccNo = G.LinkedAccNo inner join -- ... and get the   Property   for each ...
      @ACC as A on A.Property = AP.Property -- ... to find new linked rows.
      where G.Path not like '%|' + Cast( A.AccNo as VarChar(10) ) + '|%' )
  select AccNo, LinkedAccNo -- , Path
    from Groups
    order by AccNo, LinkedAccNo;