Ottenere dati coerenti albero menù dalle tabelle di menu in MySQL
-
13-09-2019 - |
Domanda
Ho un problema albero / antenato / interrogazione io non sono in grado di risolvere:
Ho una tabella che contiene dati di menu e una tabella contenente tutti gli antenati del menu:
table menu table ancestors
+-----+------------+--------+ +---------+--------------+-------+
| id | title | active | | menu_id | ancestor_id | level |
+-----+------------+--------+ +---------+--------------+-------+
| 1 | Home | 0 | | 1 | 0 | 0 |
| 2 | News | 0 | | 2 | 1 | 1 |
| 3 | Foo | 0 | | 3 | 2 | 2 |
| 4 | Bar | 1 | | 3 | 1 | 1 |
| 5 | Downloads | 1 | | 4 | 3 | 3 |
+-----+------------+--------+ | 4 | 2 | 2 |
| 4 | 1 | 1 |
| 5 | 1 | 1 |
+---------+--------------+-------+
ricevo tutte le voci di menu attivi con i loro antenati facilmente con:
SELECT menu.id, menu.title, GROUP_CONCAT(ancestors.ancestor_id) as ancestors
FROM menu, ancestors
WHERE menu.active = 1
GROUP BY (menu.id);
+----+-----------+----------+
| id | title |ancestors |
+----+-----------+----------+
| 4 | Bar | 3,2,1 |
| 5 | Downloads | 1 |
+----+-----------+----------+
Ma come posso ottenere tutte le i per l'albero antenati necessarie, troppo? Nel mio risultato che avrei bisogno l'entrata Foo e notizie in modo che ho un albero consistente. Esso dovrebbe essere simile a questo:
+----+-----------+----------+
| id | title |ancestors |
+----+-----------+----------+
| 2 | News | 1 |
| 3 | Foo | 2,1 |
| 4 | Bar | 3,2,1 |
| 5 | Downloads | 1 |
+----+-----------+----------+
Come ha la query per essere come?
Soluzione
Quando faccio questo, io la struttura della tabella di ancestors
in modo leggermente diverso. Invece di level
, devo conservare pathlength
. memorizzare anche una riga per ogni voce di menu per puntare a se stesso, con una lunghezza di percorso di 0.
+---------+--------------+------------+
| menu_id | ancestor_id | pathlength |
+---------+--------------+------------+
| 1 | 1 | 0 |
| 2 | 2 | 0 |
| 3 | 3 | 0 |
| 4 | 4 | 0 |
| 5 | 5 | 0 |
| 2 | 1 | 1 |
| 3 | 2 | 2 |
| 3 | 1 | 1 |
| 4 | 3 | 3 |
| 4 | 2 | 2 |
| 4 | 1 | 1 |
| 5 | 1 | 1 |
+---------+--------------+------------+
Queste voci "riflessivi" permettono di unire l'insieme di voci di menu attivi al tavolo di chiusura. La modifica a livello di percorso ottico consente di escludere le voci riflessive dal set di antenati.
Ora è possibile interrogare tutte le voci di menu che sono gli antenati delle voci di menu "attivi", tra le voci di menu attivi stessi:
SELECT a2.menu_id, m2.title, GROUP_CONCAT(a2.ancestor_id) AS ancestors
FROM menu m1
JOIN ancestors a1 ON (m1.id = a1.menu_id)
JOIN ancestors a2 ON (a1.ancestor_id = a2.menu_id AND a2.pathlength > 0)
JOIN menu m2 ON (a2.menu_id = m2.id)
WHERE m1.active = 1
GROUP BY a2.menu_id;
Risultato:
+---------+-----------+-----------+
| menu_id | title | ancestors |
+---------+-----------+-----------+
| 2 | News | 1 |
| 3 | Foo | 2,1 |
| 4 | Bar | 3,2,1 |
| 5 | Downloads | 1 |
+---------+-----------+-----------+