在SQL中查找顶级父级

InT*_*ons 18 sql sql-server

我有两张桌子如下

Person

  Id   Name
   1    A
   2    B
   3    C
   4    D
   5    E
Run Code Online (Sandbox Code Playgroud)

RelationHierarchy

ParentId   CHildId
   2         1
   3         2
   4         3
Run Code Online (Sandbox Code Playgroud)

这将形成树状结构

          D
          |
          C
          |
          B
          |
          A
Run Code Online (Sandbox Code Playgroud)

ParentId和ChildId是Person Table的Id列的外键

我需要编写可以获取顶级父级即根的SQL.任何人都可以建议任何可以帮助我实现这一目标的SQL

Nen*_*vic 24

您可以使用递归CTE来实现:

DECLARE @childID INT 
SET @childID  = 1 --chield to search

;WITH RCTE AS
(
    SELECT *, 1 AS Lvl FROM RelationHierarchy 
    WHERE ChildID = @childID

    UNION ALL

    SELECT rh.*, Lvl+1 AS Lvl FROM dbo.RelationHierarchy rh
    INNER JOIN RCTE rc ON rh.CHildId = rc.ParentId
)
SELECT TOP 1 id, Name
FROM RCTE r
inner JOIN dbo.Person p ON p.id = r.ParentId
ORDER BY lvl DESC
Run Code Online (Sandbox Code Playgroud)

SQLFiddle DEMO

编辑 - 为所有儿童提供最高级别父母的更新请求:

;WITH RCTE AS
(
    SELECT  ParentId, ChildId, 1 AS Lvl FROM RelationHierarchy 

    UNION ALL

    SELECT rh.ParentId, rc.ChildId, Lvl+1 AS Lvl 
    FROM dbo.RelationHierarchy rh
    INNER JOIN RCTE rc ON rh.ChildId = rc.ParentId
)
,CTE_RN AS 
(
    SELECT *, ROW_NUMBER() OVER (PARTITION BY r.ChildID ORDER BY r.Lvl DESC) RN
    FROM RCTE r

)
SELECT r.ChildId, pc.Name AS ChildName, r.ParentId, pp.Name AS ParentName
FROM CTE_RN r
INNER JOIN dbo.Person pp ON pp.id = r.ParentId
INNER JOIN dbo.Person pc ON pc.id = r.ChildId
WHERE RN =1
Run Code Online (Sandbox Code Playgroud)

SQLFiddle DEMO

EDIT2 - 让所有人在最后改变JOINS:

SELECT pc.Id AS ChildID, pc.Name AS ChildName, r.ParentId, pp.Name AS ParentName
FROM dbo.Person pc 
LEFT JOIN CTE_RN r ON pc.id = r.CHildId AND  RN =1
LEFT JOIN dbo.Person pp ON pp.id = r.ParentId
Run Code Online (Sandbox Code Playgroud)

SQLFiddle DEMo


小智 6

要查找所有顶级父级,请使用如下查询:

select p.Name
from Person p
where not exists
(select null
 from RelationHierarchy r
 where r.ChildId = p.Id)
Run Code Online (Sandbox Code Playgroud)

SQLFiddle在这里

要查找特定子级的顶级父级,请使用:

with cte as
(select t.ParentId TopParent, t.ChildId 
 from RelationHierarchy t
 left join RelationHierarchy p on p.ChildId = t.ParentId
 where p.ChildId is null
 union all
 select t.TopParent TopParent, c.ChildId 
 from cte t
 join RelationHierarchy c on t.ChildId = c.ParentId)
select p.name
from cte h
join Person p on h.TopParent = p.Id
where h.ChildId=3 /*or whichever child is required*/
Run Code Online (Sandbox Code Playgroud)

SQLFiddle在这里


小智 6

我已经使用此模式将层次结构中的项目与项目的根节点相关联.基本上递归层次结构,维护根节点的值作为附加到每一行的附加列.希望这可以帮助.

    with allRows as (
        select ItemId, ItemName, ItemId [RootId],ItemName [RootName] 
        from parentChildTable
        where ParentItemId is null
        union all
        select a1.ItemId,a1.ItemName,a2.[RootId],a2.[RootName]
        from parentChildTable a1
        join allRows a2 on a2.ItemId = a1.ParentItemId
    )   

    select * from allRows
Run Code Online (Sandbox Code Playgroud)