mysql - 从 MySQL 中的菜单表获取一致的菜单树数据

标签 mysql tree hierarchical-data ancestor

我有一个我无法解决的树/祖先/查询问题:

我有一个包含菜单数据的表和一个包含菜单所有祖先的表:

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

这些“自反”条目允许您将事件菜单项集连接到闭包表。将级别更改为路径长度允许您从祖先集中排除反身条目。

现在您可以查询作为“事件”菜单项祖先的所有菜单项,包括事件菜单项本身:

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

关于mysql - 从 MySQL 中的菜单表获取一致的菜单树数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1465175/

相关文章:

php - 根据数组获取mysql结果

mysql - SQL 中的日期范围

PHP - 如何访问深层数组的内容,动态构建它的路径

从根开始逐层遍历二叉树的算法

mysql - MySQL 中的分层查询

mysql - 在 Mysql 中为多个根存储分层数据的最佳方法是什么?

mysql - 从另一个表更新表中的值

php - 将 if 语句和多个 sql 查询合并为一个查询

data-structures - 平衡 AVL 树

python - 将 csv 转换为 Newick 树