1

커서를 사용했을 때의 문제를 해결하기 위해 CTE와 재귀를 이해하려고합니다.SQL 재귀 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의 목록을 얻는 것이며 모든 AccNo는 Property를 통해 관련되어 있습니다. 그래서 내 예상 결과는 내가 다음 코드 및 변형을 시도했습니다

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

을하지만 나는 하나가 전용 또는 I 100 재귀를 명중 4 개 결과 (PrimaryAccNo = LinkedAccNo) 얻을.

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

디버깅 정보 : CTE의 앵커에 '0으로 심도'를 추가하고 재귀 적으로 '선택'에 '심도 +1'을 추가하십시오. 재귀적인 'where' 절을 추가하여 언제든지 재귀를 중지 할 수 있습니다. '와 Depth <42'를보고 무슨 일이 일어나고 있는지 살펴보십시오. – HABO

+0

@HABO 감사합니다. 나는 이것을 봐야 할 것이다. 지금 나는 이것이 어떻게 나를 돕는 지 보지 못하고있다. – GavinP

+0

나는 모양을 보았다. 불행히도 나는 내 데이터 세트에 대해 얼마나 많은 재귀가 필요한지 알지 못한다. 위 예제에서 'Depth <2'를 사용하여 멋지고 빠르게 실행할 수 있지만 내 실제 데이터 세트에서는 내 쿼리가 실행 중이다. 'Depth <4 '로 13 분 ... ....이 문제는 유일한 새로운 match가 아니라 duplicate가 추가되는 것처럼 보입니다. 나는 커서 기반 접근 방식으로 되돌아 가야 할 것이라고 생각한다. – GavinP

답변

0

데이터 내의 순환으로 인해 무한 루프가 발생합니다 (예 : 1> 2> 3> 2> ...). 해결책은 이미 "소비"된 행을 추적하는 것입니다. CTE의 한계로 인해 각 CTE 행에 내역을 포함시켜야합니다. 경로를 조립하여 각 행에 도착합니다. 최종 select에서 , Path의 주석 처리를 제거하면 어떤 일이 일어나는지 확인할 수 있습니다.

-- 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;