Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Abfrage, um übergeordnete Datensätze mit untergeordnetem Datensatz zu erhalten, gefolgt von den nächsten übergeordneten und untergeordneten Datensätzen in MySQL

Die Lösung, die ich hier vorschlage, verwendet das Konzept des materialisierten Pfads. Das Folgende ist ein Beispiel für materialisierte Pfade unter Verwendung Ihrer Beispieldaten. Ich hoffe, es hilft Ihnen, das Konzept des materialisierten Pfads zu verstehen:

+----+--------------------------+----------+------------------+
| ID |           Name           | ParentID | MaterializedPath |
+----+--------------------------+----------+------------------+
|  1 | Parent 1                 |        0 | 1                |
|  2 | Parent 2                 |        0 | 2                |
|  4 | Parent 2 Child 1         |        2 | 2.4              |
|  6 | Parent 2 Child 1 Child 1 |        4 | 2.4.6            |
|  7 | Parent 2 Child 1 Child 2 |        4 | 2.4.7            |
|  3 | Parent 1 Child 1         |        1 | 1.3              |
|  5 | Parent 1 Child 1 Child   |        3 | 1.3.5            |
+----+--------------------------+----------+------------------+

Jeder Knoten N einen materialisierten Pfad hat, sagt Ihnen dieser Pfad, wie Sie vom Wurzelknoten zum Knoten N gehen müssen . Es kann erstellt werden, indem die Knoten-IDs verkettet werden. Zum Beispiel, um den Knoten 5 zu erreichen Ausgehend von seinem Wurzelknoten besuchen Sie den Knoten 1 , Knoten 3 und Knoten 5 , also Knoten 5 materialisierter Pfad ist 1.3.5

Zufälligerweise kann die gesuchte Reihenfolge durch den materialisierten Pfad erreicht werden.

Im vorherigen Beispiel werden materialisierte Pfade durch Verketten von Strings erstellt, aber ich bevorzuge aus mehreren Gründen die binäre Verkettung.

Um die materialisierten Pfade zu erstellen, benötigen Sie den folgenden rekursiven CTE:

CREATE TABLE Tree
(
    ID int NOT NULL CONSTRAINT PK_Tree PRIMARY KEY, 
    Name nvarchar(250) NOT NULL,
    ParentID int NOT NULL,
)

INSERT INTO Tree(ID, Name, ParentID) VALUES
(1, 'Parent 1', 0),
(2, 'Parent 2', 0),
(3, 'Parent 1 Child 1', 1),
(4, 'Parent 2 Child 1', 2),
(5, 'Parent 1 Child 1 Child', 3),
(6, 'Parent 2 Child 1 Child 1', 4),
(7, 'Parent 2 Child 1 Child 2', 4)

GO
WITH T AS
(
    SELECT
        N.ID, N.Name, N.ParentID, CAST(N.ID AS varbinary(512)) AS MaterializedPath
    FROM
        Tree N
    WHERE
        N.ParentID = 0

    UNION ALL

    SELECT
        N.ID, N.Name, N.ParentID, CAST( T.MaterializedPath + CAST(N.ID AS binary(4)) AS varbinary(512) ) AS MaterializedPath
    FROM
        Tree N INNER JOIN T
            ON N.ParentID = T.ID

)
SELECT *
FROM T
ORDER BY T.MaterializedPath

Ergebnis:

+----+--------------------------+----------+----------------------------+
| ID |           Name           | ParentID |      MaterializedPath      |
+----+--------------------------+----------+----------------------------+
|  1 | Parent 1                 |        0 | 0x00000001                 |
|  3 | Parent 1 Child 1         |        1 | 0x0000000100000003         |
|  5 | Parent 1 Child 1 Child   |        3 | 0x000000010000000300000005 |
|  2 | Parent 2                 |        0 | 0x00000002                 |
|  4 | Parent 2 Child 1         |        2 | 0x0000000200000004         |
|  6 | Parent 2 Child 1 Child 1 |        4 | 0x000000020000000400000006 |
|  7 | Parent 2 Child 1 Child 2 |        4 | 0x000000020000000400000007 |
+----+--------------------------+----------+----------------------------+

Der obige rekursive CTE beginnt mit den Wurzelknoten. Die Berechnung des materialisierten Pfads für einen Wurzelknoten ist trivial einfach, es ist die ID des Knotens selbst. Bei der nächsten Iteration verbindet der CTE Wurzelknoten mit seinen Kindknoten. Der materialisierte Pfad für einen untergeordneten Knoten CN ist die Verkettung des materialisierten Pfades seines Elternknotens PN und die ID des Knotens CN . Nachfolgende Iterationen gehen im Baum eine Ebene nach unten, bis die Blattknoten erreicht sind.