SQL Server 2012 CTE查找分层数据的根或顶级父级

raz*_*444 4 sql-server recursive-query common-table-expression hierarchical-data

我在尝试以递归方式遍历层次结构以查找可能具有多个顶级节点的组织结构中的所有后代节点的顶级节点时遇到问题.我试图使用SQL Server 2012 CTE这样做,但它不会递归到达每个分支的最顶级节点.我已经尝试过完全按照与此相关的其他帖子中显示我的查询,但仍然没有骰子.(至少我我是.)我希望有人可以告诉我这里我做错了什么?这篇文章与我正在尝试做的事情密切相关,我已经按照接受的答案,但我仍然只是"得到它":在SQL中找到顶级父级

组织表

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

我想创建一个数据库视图,列出每个OrgGroup以及他们的TOP-MOST祖先的ID.(不是他们的直接父母)

因此,例如,DB View将拥有(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
Run Code Online (Sandbox Code Playgroud)

这导致福利组织组具有最高的ParentGroupId(5)HR.期望的结果将是(4)财务.它还会导致重复记录.

来自CTE的SQL结果

至少要删除重复项,我已将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
Run Code Online (Sandbox Code Playgroud)

我在哪里?TIA

Rog*_*olf 7

两个缺点:

  • 首先,由于某种原因,您决定选择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;
Run Code Online (Sandbox Code Playgroud)


Kar*_*ger 5

您确实可以从叶节点向上走(就像您正在做的那样),找到每个原始行的根。您缺少的东西是在递归时跟踪起始叶子。精简示例:

小提琴

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*
Run Code Online (Sandbox Code Playgroud)