모든 어린이의 총계를 찾는 재귀 CTE


16

다음은 예상되는 결과를 가진 재귀 T-SQL쿼리 (아마도 CTE)를 사용하여 검색하려는 어셈블리 트리입니다 . 부품마다 주어진 어셈블리 당 총량을 알고 싶습니다.

'리벳'을 검색하면 직계 자녀 수뿐만 아니라 어셈블리 내 각 수준의 총 수를 알고 싶습니다.

Assembly (id:1)
    |
    |-Rivet
    |-Rivet
    |-SubAssembly (id:2)
    |   |
    |   |-Rivet
    |   |-Bolt
    |   |-Bolt
    |   |-SubSubAssembly (id:3)
    |      |
    |      |-Rivet
    |      |-Rivet
    |
    |-SubAssembly (id:4)
       |-Rivet
       |-Bolt

    DESIRED Results
    -------
    ID, Count
    1 , 6
    2 , 3
    3 , 2
    4 , 1

현재 직계 부모를 구할 수는 있지만이 정보를 공개 할 수 있도록 CTE를 확장하는 방법을 알고 싶습니다.

With DirectParents AS(
--initialization
Select InstanceID, ParentID
From Instances i 
Where i.Part = 'Rivet'

UNION ALL
--recursive execution
Select i.InstanceID, i.ParentID
From PartInstances i  INNER JOIN DirectParents p
on i.ParentID = p.InstanceID

)

select ParentID, Count(instanceid) as Totals
from DirectParents
group by InstanceID, ParentID

Results
-------
ID, Count
1 , 2
2 , 2
3 , 2
4 , 1

작성 스크립트

CREATE TABLE [dbo].[Instances] ( 
  [InstanceID] NVARCHAR (50) NOT NULL, 
  [Part] NVARCHAR (50) NOT NULL, 
  [ParentID] NVARCHAR (50) NOT NULL, );



INSERT INTO Instances 
Values 
  (1, 'Assembly', 0), 
  (50, 'Rivet', 1), 
  (50, 'Rivet', 1), 
  (2, 'SubAssembly', 1), 
  (50, 'Rivet', 2), 
  (51, 'Bolt', 2), 
  (51, 'Bolt', 2), 
  (3, 'SubSubAssembly', 2), 
  (50, 'Rivet', 3), 
  (50, 'Rivet', 3), 
  (4, 'SubAssembly2', 1), 
  (50, 'Rivet', 4), 
  (51, 'Bolt', 4)

답변:


14

이 재귀 CTE ( SQL Fiddle )는 샘플과 함께 작동해야합니다.

WITH cte(ParentID) AS(
    SELECT ParentID FROM @Instances WHERE [Part] = 'Rivet'
    UNION ALL
    SELECT i.ParentID FROM cte c
    INNER JOIN @Instances i ON c.ParentID = i.InstanceID
    WHERE i.ParentID > 0
)
SELECT ParentID, count(*) 
FROM cte
GROUP BY ParentID
ORDER BY ParentID
;

산출

ParentID    Count
1           6
2           3
3           2
4           1

참고 : 의견에 질문에 단순화 된 샘플 테이블 만 있고 실제 데이터에는 적절한 색인이 있고 중복 및 데이터를 적절하게 처리한다고 언급했습니다.

사용 된 데이터 ( SQL Fiddle ) :

DECLARE @Instances TABLE( 
    [InstanceID] int NOT NULL
    , [Part] NVARCHAR (50) NOT NULL
    , [ParentID] int NOT NULL
);

INSERT INTO @Instances([InstanceID], [Part], [ParentID])
VALUES 
    (1, 'Assembly', 0)
    , (50, 'Rivet', 1)
    , (50, 'Rivet', 1)
    , (2, 'SubAssembly', 1)
    , (50, 'Rivet', 2)
    , (51, 'Bolt', 2)
    , (51, 'Bolt', 2)
    , (3, 'SubSubAssembly', 2)
    , (50, 'Rivet', 3)
    , (50, 'Rivet', 3)
    , (4, 'SubAssembly2', 1)
    , (50, 'Rivet', 4)
    , (51, 'Bolt', 4)
;

큰 답변 감사합니다! 모든 인스턴스 (어셈블리, 리벳 등)에 대해 재귀 적으로이 작업을 수행하는 쉬운 솔루션이 있습니까?
greenhoorn

0

"금액"의 의미와 테이블 (?) PartInstances 및 열 ID count 가 샘플에서 샘플 데이터에서 추측 한 것을 계산했습니다.

;with ins as (
select [InstanceID], [Part],[ParentID],0 lvl
from instances where ParentID=0
union all
select i.[InstanceID], i.[Part],i.[ParentID], lvl+1
from instances i 
inner join ins on i.parentid=ins.InstanceID
)
select InstanceID,part,COUNT(*) cnt
from ins
group by instanceid,part

이것이 당신에게 몇 가지 아이디어를 줄 수 있기를 바랍니다.

최신 정보

나는 이것이 테스트 예제라는 것을 이해하지만 귀하의 데이터는에서 시작하는 모든 것을 깨뜨 1NF립니다. 아마도 테이블이 두 개로 나뉘어 정규화되어야합니다.


코드의 첫 번째 섹션에서 결과를 참조하십시오. 원하는 결과입니다. '리벳'을 검색 할 때 트리의 모든 조각에 주어진 모든 리벳을 얻으려고합니다. 인스턴스 ID 1은 6의 결과를 의미합니다. 전체 트리 구조에 총 6 개의 리벳이 포함되어 있음을 의미합니다.
markokstate
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.