How to group hierarchical relationships together in SQL Server

前端 未结 3 1843
余生分开走
余生分开走 2021-01-07 15:48

I have a column name Parent and Child in table Example and Below is the Table Data

|     Parent          |         


        
3条回答
  •  粉色の甜心
    2021-01-07 16:08

    Here is a cut-down version of the query from a more generic question How to find all connected subgraphs of an undirected graph

    The main idea is to treat (Parent,Child) pairs as edges in a graph and traverse all connected edges starting from a given node.

    Since the graph is undirectional we build a list of pairs in both directions in CTE_Pairs at first.

    CTE_Recursive follows the edges of a graph and stops when it detects a loop. It builds a path of visited nodes as a string in IDPath and stops the recursion if the new node is in the path (has been visited before).

    Final CTE_CleanResult puts all found nodes in one simple list.

    CREATE PROCEDURE GetAncestors(@thingID varchar(8000))
    AS
    BEGIN
        SET NOCOUNT ON;
    
        WITH
        CTE_Pairs
        AS
        (
            SELECT
                CAST(Parent AS varchar(8000)) AS ID1
                ,CAST(Child AS varchar(8000)) AS ID2
            FROM Example
            WHERE Parent <> Child
    
            UNION
    
            SELECT
                CAST(Child AS varchar(8000)) AS ID1
                ,CAST(Parent AS varchar(8000)) AS ID2
            FROM Example
            WHERE Parent <> Child
        )
        ,CTE_Recursive
        AS
        (
            SELECT
                ID1 AS AnchorID
                ,ID1
                ,ID2
                ,CAST(',' + ID1 + ',' + ID2 + ',' AS varchar(8000)) AS IDPath
                ,1 AS Lvl
            FROM
                CTE_Pairs
            WHERE ID1 = @thingID
    
            UNION ALL
    
            SELECT
                CTE_Recursive.AnchorID
                ,CTE_Pairs.ID1
                ,CTE_Pairs.ID2
                ,CAST(CTE_Recursive.IDPath + CTE_Pairs.ID2 + ',' AS varchar(8000)) AS IDPath
                ,CTE_Recursive.Lvl + 1 AS Lvl
            FROM
                CTE_Pairs
                INNER JOIN CTE_Recursive ON CTE_Recursive.ID2 = CTE_Pairs.ID1
            WHERE
                CTE_Recursive.IDPath NOT LIKE '%,' + CTE_Pairs.ID2 + ',%'
        )
        ,CTE_RecursionResult
        AS
        (
            SELECT AnchorID, ID1, ID2
            FROM CTE_Recursive
        )
        ,CTE_CleanResult
        AS
        (
            SELECT AnchorID, ID1 AS ID
            FROM CTE_RecursionResult
    
            UNION
    
            SELECT AnchorID, ID2 AS ID
            FROM CTE_RecursionResult
        )
        SELECT ID
        FROM CTE_CleanResult
        ORDER BY ID
        OPTION(MAXRECURSION 0);
    
    END;
    

提交回复
热议问题