Mysql
 sql >> Base de données >  >> RDS >> Mysql

Requête pour obtenir les enregistrements parents avec l'enregistrement enfant, suivis des prochains enregistrements parent-enfant dans mysql

La solution que je propose ici utilise le concept de chemin matérialisé. Voici un exemple de chemins matérialisés utilisant vos exemples de données. J'espère que cela vous aidera à comprendre le concept de chemin matérialisé :

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

Chaque nœud N a un chemin matérialisé, ce chemin vous indique le chemin pour aller du noeud racine au noeud N . Il peut être construit en concaténant les identifiants de nœud. Par exemple, pour atteindre le nœud 5 à partir de son nœud racine, vous visitez le nœud 1 , nœud 3 , et le nœud 5 , donc nœud 5 le chemin matérialisé est 1.3.5

Par coïncidence, la commande que vous recherchez peut être obtenue en commandant par le chemin matérialisé.

Dans l'exemple précédent, les chemins matérialisés consistent à concaténer des chaînes, mais je préfère la concaténation binaire pour un certain nombre de raisons.

Pour construire les chemins matérialisés, vous avez besoin du CTE récursif suivant :

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

Résultat :

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

Le CTE récursif ci-dessus commence par les nœuds racine. Le calcul du chemin matérialisé pour un nœud racine est très simple, c'est l'ID du nœud lui-même. À l'itération suivante, le CTE joint les nœuds racine avec ses nœuds enfants. Le chemin matérialisé pour un nœud enfant CN est la concaténation du chemin matérialisé de son nœud parent PN et l'id du nœud CN . Les itérations suivantes avancent d'un niveau vers le bas dans l'arbre jusqu'à ce que les nœuds feuilles soient atteints.