Heim  >  Artikel  >  Datenbank  >  Wie finde ich alle verbundenen Untergraphen in einem ungerichteten Diagramm mithilfe eines rekursiven CTE?

Wie finde ich alle verbundenen Untergraphen in einem ungerichteten Diagramm mithilfe eines rekursiven CTE?

Patricia Arquette
Patricia ArquetteOriginal
2024-10-31 06:38:30507Durchsuche

How to Find All Connected Subgraphs in an Undirected Graph Using a Recursive CTE?

So finden Sie alle verbundenen Untergraphen eines ungerichteten Graphen

Problem:

Gegeben a Tabelle mit zwei Spalten, die Bezeichner enthalten, alle Gruppen von Bezeichnern finden, die miteinander verbunden sind.

Beispieltabelle:

ID Identifier1 Identifier2
1 a c
2 b f
3 a g
4 c h
5 b j
6 d f
7 e k
8 i
9 l h

Gewünschte Ausgabe:

Identifier Gr_ID Gr.Members
a 1 (a,c,g,h,l)
b 2 (b,d,f,j)
c 1 (a,c,g,h,l)
d 2 (b,d,f,j)
e 3 (e,k)
f 2 (b,d,f,j)
g 1 (a,c,g,h,l)
h 1 (a,c,g,h,l)
j 2 (b,d,f,j)
k 3 (e,k)
l 1 (a,c,g,h,l)
i 4 (i)

Lösung:

Die folgende Abfrage verwendet eine einzige rekursive Abfrage, um alle verbundenen Untergraphen zu finden:

<code class="sql">WITH
CTE_Idents
AS
(
    SELECT Ident1 AS Ident
    FROM @T

    UNION

    SELECT Ident2 AS Ident
    FROM @T
)
,CTE_Pairs
AS
(
    SELECT Ident1, Ident2
    FROM @T
    WHERE Ident1 <> Ident2

    UNION

    SELECT Ident2 AS Ident1, Ident1 AS Ident2
    FROM @T
    WHERE Ident1 <> Ident2
)
,CTE_Recursive
AS
(
    SELECT
        CAST(CTE_Idents.Ident AS varchar(8000)) AS AnchorIdent 
        , Ident1
        , Ident2
        , CAST(',' + Ident1 + ',' + Ident2 + ',' AS varchar(8000)) AS IdentPath
        , 1 AS Lvl
    FROM 
        CTE_Pairs
        INNER JOIN CTE_Idents ON CTE_Idents.Ident = CTE_Pairs.Ident1

    UNION ALL

    SELECT 
        CTE_Recursive.AnchorIdent 
        , CTE_Pairs.Ident1
        , CTE_Pairs.Ident2
        , CAST(CTE_Recursive.IdentPath + CTE_Pairs.Ident2 + ',' AS varchar(8000)) AS IdentPath
        , CTE_Recursive.Lvl + 1 AS Lvl
    FROM
        CTE_Pairs
        INNER JOIN CTE_Recursive ON CTE_Recursive.Ident2 = CTE_Pairs.Ident1
    WHERE
        CTE_Recursive.IdentPath NOT LIKE CAST('%,' + CTE_Pairs.Ident2 + ',%' AS varchar(8000))
)
,CTE_RecursionResult
AS
(
    SELECT AnchorIdent, Ident1, Ident2
    FROM CTE_Recursive
)
,CTE_CleanResult
AS
(
    SELECT AnchorIdent, Ident1 AS Ident
    FROM CTE_RecursionResult

    UNION

    SELECT AnchorIdent, Ident2 AS Ident
    FROM CTE_RecursionResult
)
SELECT
    CTE_Idents.Ident
    ,CASE WHEN CA_Data.XML_Value IS NULL 
    THEN CTE_Idents.Ident ELSE CA_Data.XML_Value END AS GroupMembers
    ,DENSE_RANK() OVER(ORDER BY 
        CASE WHEN CA_Data.XML_Value IS NULL 
        THEN CTE_Idents.Ident ELSE CA_Data.XML_Value END
    ) AS GroupID
FROM
    CTE_Idents
    CROSS APPLY
    (
        SELECT CTE_CleanResult.Ident+','
        FROM CTE_CleanResult
        WHERE CTE_CleanResult.AnchorIdent = CTE_Idents.Ident
        ORDER BY CTE_CleanResult.Ident FOR XML PATH(''), TYPE
    ) AS CA_XML(XML_Value)
    CROSS APPLY
    (
        SELECT CA_XML.XML_Value.value('.', 'NVARCHAR(MAX)')
    ) AS CA_Data(XML_Value)
WHERE
    CTE_Idents.Ident IS NOT NULL
ORDER BY Ident;</code>

Beispielausgabe:

Identifier Gr_ID Gr.Members
a 1 (a,c,g,h,l)
b 2 (b,d,f,j)
c 1 (a,c,g,h,l)
d 2 (b,d,f,j)
e 3 (e,k)
f 2 (b,d,f,j)
g 1 (a,c,g,h,l)
h 1 (a,c,g,h,l)
i 4 (i)
j 2 (b,d,f,j)
k 3 (e,k)
l 1 (a,c,g,h,l)
z 5 (z)

Erklärung:

  • Die Abfrage verwendet einen rekursiven CTE, um alle Pfade im Diagramm zu finden, die den in der CTE_Pairs-Tabelle definierten Kanten folgen.
  • Die Die Tabelle CTE_Idents enthält alle eindeutigen Bezeichner im Diagramm.
  • Die Tabelle CTE_CleanResult extrahiert die verbundenen Bezeichner für jeden Ankerbezeichner.
  • Die abschließende SELECT-Anweisung verwendet eine Kombination aus FOR XML PATH und CROSS APPLY Verketten Sie die verbundenen Bezeichner für jede Gruppe.
  • DENSE_RANK() wird verwendet, um jeder Gruppe eindeutige Gruppen-IDs zuzuweisen.

Das obige ist der detaillierte Inhalt vonWie finde ich alle verbundenen Untergraphen in einem ungerichteten Diagramm mithilfe eines rekursiven CTE?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn