Finding Top level parent of each row of a table [SQL Server 2008]

前端 未结 3 759
醉话见心
醉话见心 2021-01-23 12:24

I have following two tables

Table Person

Id   Name
   1    A
   2    B
   3    C
   4    D
   5    E

Table RelationHierarchy



        
3条回答
  •  伪装坚强ぢ
    2021-01-23 12:52

    I have also updated the answer in the original question, but never-mind, here is a copy also:

    ;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 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
    

    SQLFiddle DEMO

    Note that the slight difference is in recursive part of CTE. ChildID is now rewritten each time from the anchor part. Also addition is ROW_NUMBER() function (and new CTE) to get the top level for each child at the end.

    EDIT - Version2

    After finding a performance issues with first query, here is an improved version. Going from top-to-bottom, instead of other way around - eliminating creating of extra rows in CTE, should be much faster on high number of recursions:

    ;WITH RCTE AS
    (
        SELECT  ParentId, CHildId, 1 AS Lvl FROM RelationHierarchy r1
        WHERE NOT EXISTS (SELECT * FROM RelationHierarchy r2 WHERE r2.CHildId = r1.ParentId)
    
        UNION ALL
    
        SELECT rc.ParentId, rh.CHildId, Lvl+1 AS Lvl 
        FROM dbo.RelationHierarchy rh
        INNER JOIN RCTE rc ON rc.CHildId = rh.ParentId
    )
    SELECT pc.Id AS ChildID, pc.Name AS ChildName, r.ParentId, pp.Name AS ParentName
    FROM dbo.Person pc 
    LEFT JOIN RCTE r ON pc.id = r.CHildId
    LEFT JOIN dbo.Person pp ON pp.id = r.ParentId 
    

    SQLFiddle DEMO

提交回复
热议问题