Finding Top Level Parent ID

前端 未结 3 1581
挽巷
挽巷 2021-01-28 10:10

In one table I have two columns like below

ID  ParentID
1   0x0
2   1
3   2
9   0x0
5   9
6   5
25  0x0
30  25

How to get top level parent ID

3条回答
  •  猫巷女王i
    2021-01-28 10:49

    If the top-level node always follows a single path to a single leaf node, then the desired result can be achieved by combining Breadcrumbs and recursive CTEs. The following example demonstrates the approach:

    CREATE TABLE #Items
    (
        ID              INT
        ,[ParentID]     INT
    )
    
    INSERT INTO #Items
    VALUES
    (1,     0x0),
    (2,     1),
    (3,     2),
    (9,     0x0),
    (5,     9),
    (6,     5),
    (25,    0x0),
    (30,    25)
    
    
    
    ;WITH CTE_Breadcrumbs
    AS
    (
        SELECT      ID
                    ,ParentID
                    ,CAST(ID AS NVARCHAR(1000)) AS [Path]
                    ,LEN(CAST(ID AS NVARCHAR(1000))) AS [PathLength]
                    ,ID AS [RootNodeID]
        FROM        #Items
        WHERE       ParentID = 0x0
        UNION ALL
        SELECT       Child.ID
                    ,Child.ParentID
                    ,CAST(Parent.[Path] + N'\' + CAST(Child.ID AS NVARCHAR(1000)) AS NVARCHAR(1000)) AS [Path]
                    ,LEN(CAST(Parent.[Path] + N'\' + CAST(Child.ID AS NVARCHAR(1000)) AS NVARCHAR(1000))) AS [PathLength]
                    ,CAST(
                        CASE 
                            WHEN CHARINDEX('\', [Path]) > 0 THEN LEFT([Path], CHARINDEX('\', [Path]) - 1)
                            ELSE Child.ParentID
                        END
                    AS INT)  AS [RootNodeID]
        FROM        #Items Child 
        INNER JOIN  CTE_Breadcrumbs Parent ON Child.ParentID = Parent.ID
    )
    ,
    CTE_FullPathID
    AS
    (
        SELECT      [RootNodeID]
                    ,MAX([PathLength]) AS [PathFullLength]
        FROM        CTE_Breadcrumbs
        GROUP BY    [RootNodeID]
    
    )
    SELECT      CTE_Breadcrumbs.RootNodeID
                ,CAST(
                    REVERSE(
                                CASE 
                                    WHEN CHARINDEX('\', REVERSE([Path])) > 0 THEN LEFT(REVERSE([Path]), CHARINDEX('\', REVERSE([Path])) - 1)
                                    ELSE NULL
                                END
                            )
                AS INT)  AS [LeafNodeID]
                ,CTE_Breadcrumbs.[Path]
    FROM        CTE_Breadcrumbs 
    INNER JOIN  CTE_FullPathID ON CTE_Breadcrumbs.[RootNodeID] = CTE_FullPathID.[RootNodeID] AND CTE_Breadcrumbs.PathLength = CTE_FullPathID.[PathFullLength]
    

提交回复
热议问题