2

최상위 노드를 가질 수있는 조직 구조에서 모든 하위 노드의 최상위 노드를 찾기 위해 재귀 적으로 계층 구조를 탐색하는 데 문제가 있습니다. . 나는 그렇게하기 위해 SQL Server 2012 CTE를 사용하려고 시도하고 있지만, 각 브랜치의 맨 위 노드에 도달하는 것을 반복하지는 않을 것입니다. 이것에 관한 다른 게시물에 나와 있듯이 내 쿼리를 정확하게 작성하려고 시도했지만 여전히 주사위가 없습니다. (적어도 라고 생각하면입니다.) 누군가 내가 여기서 잘못하고 있다고 말할 수 있기를 바랍 니? 이 포스팅은 가장 가까운 내가 뭘하려는거야에 관한 내가 허용 답변을 따랐습니다,하지만 난 여전히 "를 받고"아니에요 : Finding a Top Level Parent in SQLSQL Server 2012 CTE 계층 구조 데이터의 루트 또는 상위 부모 찾기

OrgGroups Table

위와 같이, 내가 가진 OrgGroups 최상위 수준이 아니고 NULL이 아닌 경우 직접 상위 그룹을 참조합니다. 예 : (4) 재정 (최상위) -> (5) HR-> (11) 이점

각 조직 그룹을 TOP-MOST 조상의 ID와 함께 나열하는 데이터베이스보기를 만들고 싶습니다. (직접 부모가 아닌)

예를 들어, DB보기에는 (11) Benefits OrgGroup에 대한 레코드와 (4) Finance의 최상위 parentgroupId에 해당하는 열 값이 있습니다.

;WITH OrgStructureIndex AS 
(
    SELECT O.OrgGroupId, O.Name, O.OrgStructureId, O.ParentGroupId, 1 AS Lvl 
    FROM OrgGroups O 

    UNION ALL 

    SELECT OG.OrgGroupId, OG.Name, OG.OrgStructureId, OG.ParentGroupId, Lvl+1 AS Lvl 
    FROM OrgGroups OG INNER JOIN OrgStructureIndex OI 
    ON OI.OrgGroupId = OG.ParentGroupId 
) 

SELECT * FROM OrgStructureIndex 

이로 인해 Benefits org 그룹의 상위 5 개 HR 그룹이 상위에 있습니다. 원하는 결과는 (4) 재정이 될 것입니다. 또한 중복 레코드가됩니다.

SQL Results from CTE above

는 중복을 제거하기 위해 적어도, 나는 내 SQL을 변경했습니다 :

;WITH OrgStructureIndex AS 
(
    SELECT O.OrgGroupId, O.Name, O.OrgStructureId, O.ParentGroupId, 1 AS Lvl 
    FROM OrgGroups O 

    UNION ALL 

    SELECT OG.OrgGroupId, OG.Name, OG.OrgStructureId, OG.ParentGroupId, Lvl+1 AS Lvl 
    FROM OrgGroups OG INNER JOIN OrgStructureIndex OI 
    ON OI.OrgGroupId = OG.ParentGroupId 
) 
,CTE_RN AS 
(
    SELECT *, ROW_NUMBER() OVER (PARTITION BY oi.OrgGroupId ORDER BY oi.Lvl DESC) RN 
    FROM OrgStructureIndex oi 
) 

SELECT * FROM CTE_RN 
WHERE RN = 1 

가 어디 짧은 여기 하락하고 ?? TIA

답변

5

두 단점 :

  • 먼저, CTE뿐만 아니라 루트 사람의 앵커 파트의 모든 노드를 선택하기로 결정 어떤 이유로. 그래서 당신은 많은 중복을 가지고 있습니다.
  • 둘째, 실제로 필요한 유일한 필드 (실제 루트의 Id)는 전달하지 않습니다. 여기

당신이 그들을 고칠 수있는 방법입니다

;WITH OrgStructureIndex AS 
(
    SELECT O.OrgGroupId, O.Name, O.OrgStructureId, O.ParentGroupId, 1 AS Lvl, 
     -- #2 
     o.OrgGroupId as [RootGroupId] 
    FROM OrgGroups O 
    -- #1 
    where o.ParentGroupId is null 
    UNION ALL 
    SELECT OG.OrgGroupId, OG.Name, OG.OrgStructureId, OG.ParentGroupId, Lvl+1 AS Lvl, 
     -- #2 
     oi.RootGroupId 
    FROM OrgGroups OG INNER JOIN OrgStructureIndex OI 
    ON OI.OrgGroupId = OG.ParentGroupId 
) 
SELECT * FROM OrgStructureIndex; 
+0

아! 네, ParentGroupId를 한 점에서 null로 설정 했으므로 많은 일들이 뒤죽박죽이었습니다. 다시 넣어 두는 것을 잊었습니다. 나는 당신의 제안을 시도 할 것입니다! – razaross444

+0

굉장! 아름답게 작동합니다. Roger. 감사합니다! – razaross444

2

당신은 실제로 잎 노드에서 걸어 수 있습니다 - 당신이하고있는 것처럼 - 각 원래 행의 루트를 찾을 수 있습니다. 재발행하면서 누락 된 부분이 시작 잎을 추적하고있는 것입니다. 아래로 벗겨진 예 :

fiddle

CREATE TABLE OrgGroup (OrgGroupId INT, Name VARCHAR(10), ParentGroupId INT) 
GO 

INSERT INTO OrgGroup VALUES 
(1,'Main', NULL), 
(2,'IT',1), 
(3,'DotCom',2), 
(4,'Finance', NULL), 
(5,'HR',4), 
(6,'Accounting',4) 

GO 

;WITH cte AS 
(
    SELECT 1 AS Lvl 
     ,OrgGroupId LeafId 
     ,OrgGroupId 
     ,ParentGroupId 
     ,Name 
     ,Name LeafName 

    FROM OrgGroup 

    UNION ALL 



    SELECT Lvl+1 AS Lvl 
     ,OI.LeafId 
     ,OG.OrgGroupId 
     ,OG.ParentGroupId 
     ,OG.Name 
     ,OI.LeafName 
    FROM OrgGroup OG 
      INNER JOIN 
      cte OI ON OI.ParentGroupId = OG.OrgGroupId 
) 
,cte_rn AS (
SELECT * 
     ,ROW_NUMBER() OVER (PARTITION BY LeafID ORDER BY Lvl DESC) rn 
    FROM cte 
) 
SELECT * FROM cte_rn WHERE rn = 1* 
+0

Karl, 나는 솔루션을 시험해보고 심지어 구조에 또 다른 레벨을 추가했으며 Roger의 솔루션처럼 의도 한 결과를 달성합니다. 항상 한 가지 이상의 방법을 사용하는 것이 좋습니다. :) 감사! – razaross444