【问题标题】:Getting consistent menu tree data from menu tables in MySQL从 MySQL 的菜单表中获取一致的菜单树数据
【发布时间】:2009-09-23 10:25:31
【问题描述】:

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

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

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

查询是什么样的?

【问题讨论】:

    标签: mysql tree hierarchical-data ancestor


    【解决方案1】:

    执行此操作时,ancestors 表的结构略有不同。我存储pathlength,而不是level。还为每个菜单项存储一行以指向自身,路径长度为 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         | 
    +---------+-----------+-----------+
    

    【讨论】:

    • 谢谢比尔。您如何将值放入您的路径长度列?我正在使用您的 SQL Antipatterns 书中的插入和更新查询。谢谢!
    • 比尔,在您网站上的评论中找到了您的答案!可以在这里找到:link 非常感谢!
    猜你喜欢
    • 1970-01-01
    • 2014-08-03
    • 2012-09-03
    • 2021-02-01
    • 2012-05-06
    • 1970-01-01
    • 2011-03-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多