在分层表中获取子节点的根父节点

8

我有一张包含层级数据的表,结构如下:

ID      ParentId
----   ----------
1       NULL
2       1
3       2
4       2
5       3
6       5

如果我传递节点ID,我想通过在SQL中遍历所有父节点来获取最顶层的节点ID/详细信息。
我尝试了CTE,但是无法正确组合。然而,我把它作为一个函数工作,但速度非常慢,所以我不得不发布这个问题。
在上面的示例中,如果我传递6,我想要最顶层的即1。通过遍历6 => 5 => 3 => 2 => [1](结果)。
提前感谢您的帮助。

CTE是公共表达式。 - Immortal
5个回答

11
DECLARE @id INT = 6
;WITH parent AS
(
    SELECT id, parentId, 1 AS [level] from tbl WHERE id = @id
    UNION ALL 
    SELECT t.id, t.parentId, [level] + 1 FROM parent
    INNER JOIN tbl t ON t.id =  parent.parentid
)
SELECT TOP 1 id FROM parent ORDER BY [level] DESC

@TechDo的回答假设最低ID将是父级。如果您不想依赖此,则上述查询将按深度排序。

这应该是被接受的答案。如果根节点具有更高的ID(这是常见情况),TechDos的答案将给出错误的结果。 - Mathias F
有没有办法扩展这个功能,以获取每个ID的根父ID? - Avin Kavish
@AvinKavish 如果我理解正确的话,我认为你可以创建一个带有上述查询的函数,然后在自己的查询中使用该函数来获取每个ID的根ID。 - Douglas Marttinen

7

请尝试以下方法:

declare @id int=6
;WITH parent AS
(
    SELECT id, parentId  from tbl WHERE id = @id
    UNION ALL 
    SELECT t.id, t.parentId FROM parent
    INNER JOIN tbl t ON t.id =  parent.parentid
)

SELECT TOP 1 id FROM  parent
order by id asc

1
这是否假定根ID是树中最低的ID?如果根ID比其他节点的ID更高怎么办? - Mathias F

2

您可以尝试使用以下查询语句来获取所有 ID:

with tab1(ID,Parent_ID) as
(select * from table1 where id = 6
union all
select t1.* from table1 t1,tab1 
where tab1.Parent_ID = t1.ID)
select ID from tab1;

这个查询将会得到最终的结果:
with tab1(ID,Parent_ID) as
(select * from table1 where id = 6
union all
select t1.* from table1 t1,tab1 
where tab1.Parent_ID = t1.ID)
select ID from tab1 where parent_id is null;

SQL Fiddle


2
 WITH CTE_MyTable AS (
    SELECT        Id, ParentId, NULL As RootParent, 1 As Lvl
    FROM            dbo.MyTable
    UNION ALL
    SELECT        a.id, b.ParentId, a.ParentId As RootParent, Lvl + 1
    FROM            CTE_MyTable a INNER JOIN
                                               dbo.MyTable b ON a.ParentId = b.Id
)
, CTE_MyTable_RN AS  (
    SELECT Id, RootParent, ROW_NUMBER() OVER (PARTITION BY Id ORDER BY Lvl DESC) RN
    FROM CTE_MyTable
)

SELECT Id, ISNULL(RootParent, Id) As RootParent
FROM CTE_MyTable_RN
WHERE RN = 1

1
;WITH CTE
as
(
    Select I.ID,P.Parent_id
    from #temp I 
    join #temp P 
    on P.Id = I.Parent_Id
    where i.ID = 6
    union all
    Select I.ID,P.Parent_id
    from CTE I 
    join #temp P 
    on P.Id = I.Parent_Id
    where p.Parent_Id is not null
)
Select ID,min(parent_id) from CTE group by id;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接