Получение согласованных данных дерева меню из таблиц меню в MySQL
-
13-09-2019 - |
Вопрос
У меня есть проблема с деревом / предком / запросом, которую я не в состоянии решить:
У меня есть таблица, содержащая данные меню, и таблица, содержащая всех предков меню:
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 |
+---------+--------------+-------+
Я легко получаю все активные пункты меню с их предками с помощью:
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 |
+----+-----------+----------+
Но как я могу получить все необходимые предки для дерева тоже?В моем результате мне понадобились бы записи Foo и News, чтобы я получил согласованное дерево.Это должно выглядеть примерно так:
+----+-----------+----------+
| id | title |ancestors |
+----+-----------+----------+
| 2 | News | 1 |
| 3 | Foo | 2,1 |
| 4 | Bar | 3,2,1 |
| 5 | Downloads | 1 |
+----+-----------+----------+
Каким должен быть запрос?
Решение
Когда я делаю это, я структурирую ancestors
таблица немного отличается.Вместо того , чтобы level
, Я храню pathlength
.Также сохраните строку для каждого пункта меню, указывающего на самого себя, с длиной пути 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 |
+---------+--------------+------------+
Эти "рефлексивные" записи позволяют вам присоединить набор активных пунктов меню к таблице закрытия.Изменение level на pathlength позволяет исключить рефлексивные записи из набора предков.
Теперь вы можете запрашивать все пункты меню, которые являются предшественниками "активных" пунктов меню, включая сами активные пункты меню:
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;
Результат:
+---------+-----------+-----------+
| menu_id | title | ancestors |
+---------+-----------+-----------+
| 2 | News | 1 |
| 3 | Foo | 2,1 |
| 4 | Bar | 3,2,1 |
| 5 | Downloads | 1 |
+---------+-----------+-----------+