2

我遇到了一个问题,试图递归地遍历层次结构,以查找组织结构中所有后代节点的顶级节点,该组织结构可能有多个顶级节点。我试图使用SQL Server 2012 CTE来做到这一点,但它不会递归到达每个分支的顶级节点。我已经尝试写下我的查询,如其他与此相关的帖子所示,但仍然没有骰子。 (至少我认为我是。)我希望有人能告诉我我在这里做错了什么?这个职位最密切涉及到我想要做的,我已经试过了公认的答案,但我仍然只是没有“得到它”:Finding a Top Level Parent in SQLSQL Server 2012 CTE找到根级别或顶级父级的分层数据

OrgGroups Table

如上图所示,我有OrgGroups引用直接父组,除非它是顶级,然后它是NULL。例如,(4)财务(顶级) - >(5)人力资源 - >(11)福利

我想创建一个数据库视图,列出每个组合的连同其TOP-MOST祖先的ID。 (不是他们的直接父母)

因此,例如,DB视图将具有(11)BenefitsOrgGroup的记录以及它的(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 

这会导致福利组织具有(5)HR的最高ParentGroupId。期望的结果将是(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在那里是空的,并且一直在搞这样的事情,我忘了把它放回去。我会尝试你的建议! – razaross444 2014-11-20 22:28:49

+0

真棒!精美的作品罗杰。非常感谢! – razaross444 2014-11-20 22:35:03

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,I摆弄你的解决方案,甚至在结构上增加了另一个层次,它就像Roger的解决方案一样达到了预期的效果。总是很高兴有不止一种方式。 :) 谢谢! – razaross444 2014-11-20 22:43:04