我在尝试递归遍历层次结构以找到组织结构中可能具有多个顶级节点的所有后代节点的顶级节点时遇到问题。我试图使用SQL Server 2012 CTE这样做,但它不会递归到达每个分支的最顶层节点。我已经尝试过完全按照与此相关的其他帖子中显示我的查询,但仍然没有骰子。 (至少我想想我是。)我希望有人可以告诉我这里我做错了什么?这篇文章与我试图做的事情最为密切相关,并且我已经按照公认的答案,但我仍然没有"得到它" :Finding a Top Level Parent in SQL
如上所示,我有OrgGroups
引用直接父组,除非它是顶级,然后它是NULL。例如,(4)财务(顶级) - > (5)HR-> (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
这导致福利组织组具有最高的ParentGroupId(5)HR。期望的结果将是(4)财务。它还会导致重复记录。
至少要删除重复项,我已将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
答案 0 :(得分:7)
两个缺点:
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;
答案 1 :(得分:3)
您确实可以从叶节点向上走 - 正如您所做的那样 - 找到每个原始行的根。你丢失的东西是在你追赶时跟踪起始叶子。剥离的例子:
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*