Mysql
 sql >> Database >  >> RDS >> Mysql

Query per ottenere record padre con record figlio, seguiti dai record padre-figlio successivi in ​​mysql

La soluzione che propongo qui utilizza il concetto di percorso materializzato. Quello che segue è un esempio di percorsi materializzati che utilizzano i dati di esempio. Spero che ti aiuti a capire il concetto di percorso materializzato:

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

Ogni nodo N ha un percorso materializzato, questo percorso ti dice la strada per andare dal nodo radice al nodo N . Può essere compilato concatenando gli ID dei nodi. Ad esempio, per raggiungere il nodo 5 partendo dal suo nodo principale, visiti il ​​nodo 1 , nodo 3 e il nodo 5 , quindi nodo 5 il percorso materializzato è 1.3.5

Per coincidenza, l'ordine che stai cercando può essere ottenuto ordinando dal percorso materializzato.

Nell'esempio precedente, i percorsi materializzati sono stringhe concatenate, ma preferisco la concatenazione binaria per una serie di motivi.

Per costruire i percorsi materializzati è necessario il seguente CTE ricorsivo:

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

Risultato:

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

Il CTE ricorsivo di cui sopra inizia con i nodi radice. Calcolare il percorso materializzato per un nodo radice è banalmente semplice, è l'ID del nodo stesso. Nell'iterazione successiva il CTE unisce i nodi radice con i suoi nodi figlio. Il percorso materializzato per un nodo figlio CN è la concatenazione del percorso materializzato del suo nodo padre PN e l'id del nodo CN . Le iterazioni successive avanzano di un livello verso il basso sull'albero fino a raggiungere i nodi foglia.