Получение согласованных данных дерева меню из таблиц меню в MySQL

StackOverflow https://stackoverflow.com/questions/1465175

Вопрос

У меня есть проблема с деревом / предком / запросом, которую я не в состоянии решить:

У меня есть таблица, содержащая данные меню, и таблица, содержащая всех предков меню:

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         | 
+---------+-----------+-----------+
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top