【问题标题】:MySQL modified preorder tree traversal - getting a subtree based on a nodeMySQL修改前序树遍历——基于节点获取子树
【发布时间】:2013-01-31 19:30:30
【问题描述】:

根据picture here on sitepont,我有一个标准的 mptt 树表。不过,我终其一生都无法找到基于所选节点获取整个子树的好方法。

示例(来自该链接页面):假设树是一个菜单,如果有人选择“Cherry” - 我想从“Fruit”节点向下获取所有项目。

所以,我可以使用

获得最终的父行(不包括我不想要的根)
SELECT lft, rgt FROM menu_items
WHERE lft < (SELECT lft FROM menu_items WHERE id = 'Cherry') 
AND rgt > (SELECT rgt FROM menu_items WHERE id = 'Cherry') 
AND lft > 1
ORDER BY lft ASC LIMIT 1

我认为 3 个 SELECT 的 SQL 非常糟糕——但它确实让我得到了 lft 和 rgt,我可以在进一步的查询中使用它来获取 lft 和 rgt 之间的所有节点——从而得到“Cherry”所在的子树。

我以此为基础在一个查询中完成所有操作 - 这导致了这种可恶:

SELECT * FROM menu_items 
WHERE lft BETWEEN 
    (SELECT lft FROM  menu_items
    WHERE lft < (SELECT lft FROM menu_items WHERE id = 'Cherry') 
    AND rgt > (SELECT rgt FROM menu_items WHERE id = 'Cherry') 
    AND lft > 1
    ORDER BY lft ASC LIMIT 1)
AND 
    (SELECT rgt FROM  menu_items
    WHERE lft < (SELECT lft FROM menu_items WHERE id = 'Cherry') 
    AND rgt > (SELECT rgt FROM menu_items WHERE id = 'Cherry') 
    AND lft > 1
    ORDER BY lft ASC LIMIT 1)
ORDER BY lft ASC;

这对我来说似乎很讨厌 - 七个 SELECTs !

这可以优雅地完成吗(最好在一个查询中,但没那么重要 - 可读性 > 单个查询)?

顺便说一句 - lft 和 rgt 是我的 MPTT 编号字段名称

编辑 ::: 实验后我意识到我笨拙的 SQL 并没有做我想要的。它仅适用于比根深 > 2 层的节点。

我的问题是:参考帖子顶部链接的图表 - 如果用户“选择”子树的任何叶子或父节点,我需要获取整个子树,不包括根。

因此,如果用户选择“Cherry”、“Banana”、“Red”、“Yellow”或“Fruit”,我需要整个“Fruit”子树。

【问题讨论】:

    标签: mysql sql tree binary-tree tree-traversal


    【解决方案1】:

    试试下面的查询:

    SELECT menu_items.* FROM menu_items ,
    (SELECT lft as lft_inner,rgt as rgt_inner FROM menu_items WHERE id = 'Cherry')  
    as menu_innner 
    WHERE lft < lft_inner  
    AND rgt > rgt_inner
    AND lft > 1
    ORDER BY lft ASC
    

    【讨论】:

    • 这已经接近了 - 但它并不完全在那里。参考帖子顶部链接的站点图,这个查询让我得到了Fruit, Red, Cherry 子树,但没有得到Yellow, Banana 分支。我今天就玩一下这个SQL,看看能不能稍微修改一下。感谢您的回答。
    • 我已经稍微编辑了我的问题 - 我的 SQL 没有按预期工作。
    • @AndyLastname 我建议你尝试使用多个 SQL,在单个查询中似乎很难实现。最初我以为你只需要子树 Fruit >> Red >> Cherry 。
    【解决方案2】:
    ------------------------------------------------------------------
    SELECT yourtable.* FROM yourtable ,
    (SELECT lft as lft_inner,rgt as rgt_inner FROM yourtable WHERE id=178)  
    as menu_innner 
    WHERE lft > lft_inner  
    AND rgt < rgt_inner
    AND lft > 1
    ORDER BY lft ASC
    -----------------------------------------------------------------------
    

    【讨论】:

      猜你喜欢
      • 2016-07-14
      • 1970-01-01
      • 2011-10-17
      • 1970-01-01
      • 2011-12-01
      • 2013-01-12
      • 1970-01-01
      • 2012-04-13
      • 1970-01-01
      相关资源
      最近更新 更多