0

我在 PHP 中使用功能齐全的嵌套集系统
我正在使用它来构建一个最大深度 = 2 的简单菜单结构

现在我在表格中添加了一个额外的字段来控制每个菜单项的可见性状态,换句话说,它是否处于活动状态。我的需要是,如果我停用父母,我希望查询不会返回任何孩子,即使他们处于活动状态。

这是检索整个菜单树的实际代码

SELECT    `nesty`.*,
          (COUNT(`parent`.`id`) - (`sub_tree`.`depth` + 1)) AS `depth`

FROM      `menus` AS `nesty`,
          `menus` AS `parent`,
          `menus` AS `sub_parent`,
          (
             SELECT `nesty`.`id`,
                    (COUNT(`parent`.`id`) - 1) AS `depth`

             FROM   `menus` AS `nesty`,
                    `menus` AS `parent`

             WHERE  `nesty`.`lft`  BETWEEN `parent`.`lft` AND `parent`.`rgt`
             AND    `nesty`.`id`     = 1
             AND    `nesty`.`tree_id`  = 1
             AND    `parent`.`tree_id` = 1

             GROUP BY `nesty`.`id`

             ORDER BY `nesty`.`lft`
          ) AS `sub_tree`

WHERE    `nesty`.`lft`   BETWEEN `parent`.`lft`     AND `parent`.`rgt`
AND      `nesty`.`lft`   BETWEEN `sub_parent`.`lft` AND `sub_parent`.`rgt`
AND      `sub_parent`.`id` = `sub_tree`.`id`
AND      `nesty`.`tree_id`   = 1
AND      `parent`.`tree_id`  = 1
GROUP BY `nesty`.`id`

HAVING   `depth` > 0

ORDER BY `nesty`.`lft`

所以基本上我想在where子句中添加

AND      `nesty`.`visible`   = 1

如果我补充说,只要停用项目不是某人的父项,它就可以正常工作所以我需要如果可见字段等于 0 和/或其父项的可见字段等于 0,则不返回菜单项

提前谢谢

4

4 回答 4

0

我很抱歉这么说,但是嵌套库确实是糟糕的技术。这是一个不太理想的嵌套集实现。永远不应该计算深度,深度场应该是数据模型的一部分,如维基百科http://en.wikipedia.org/wiki/Nested_set_model中所示。此外,永远不应该使用上面的查询来返回完整的树。只有子树需要所有这些复杂性。

请尝试这个新补丁:

= AND      `parent`.`tree_id`  = 1
+ and      nesty.lft not in (
         select menus.lft
         from   menus,
                (select     lft, rgt
                 from       menus
                 where      menus.visible = 0
                 and        menus.tree_id = 1
                ) as hidden
         where  menus.lft between hidden.lft and hidden.rgt
         and    menus.tree_id = 1
                          )

而且,如果表菜单包含深度字段,则完整树的完整查询是:

select     nesty.*, 0 as depth0
from       menus as nesty,
           (select lft, rgt from menus where menus.id = 1) as root
where      nesty.lft between root.lft and root.rgt
and        nesty.tree_id  = 1
and        not nesty.lft in (
                select    menus.lft
                from      menus,
                          (select lft, rgt
                           from   menus
                           where  visible = 0
                           and    menus.tree_id = 1
                          ) as hidden
                where     menus.lft between hidden.lft and hidden.rgt
                and       menus.tree_id = 1
                            )
于 2013-03-28T13:29:57.380 回答
0

我写了你所指的包和那个查询。它基于Mike Hillyer 的这篇博文

三个隐式连接都用于获得每个结果中相对于父级的“深度”属性,使用修改的预序树遍历算法。

我通常所做的是从您的数据库中获取节点树,就像您正在做的那样。渲染它们时,请查看每个节点的“可见性”属性。我假设您使用的是库存标准,带有 CRUD 模型。所以:

// 循环遍历你的节点 if ( !$node->visibility) continue;

当您从查询中输出结果时,您可以执行类似的操作。

Nested-Sets 2,对 Nesty 的重写使用查询生成illuminate/database器编写了该查询,而不仅仅是(实际上)普通的 SQL。我们可以注入闭包之类的东西来修改查询。

于 2013-03-27T20:55:43.817 回答
0

首先,让我祝贺您发布的非常易读的 SQL 语句。否则我不会花时间在它上面。

不幸的是,我仍然觉得这个陈述很难理解,我不能避免认为这个陈述不应该那么复杂。嵌套集应该通过避免为树的每个级别引用表来使递归查询变得简单,这似乎是您正在做的事情。

检索菜单的任何子树的查询应该很简单:

select menus.*
from menus
where menus.id between [plft] and [prgt]

其中 plft 和 prgt 是由子树根节点的左右值定义的参数。如果您的主树根的 id=1,那么您可以编写:

select menus.*
from menus
where menus.id between (select lft from menus where id=1) and 
                       (select rgt from menus where id=1)

我将根据这个典型的嵌套集合查询提供未经测试的答案。

第一步是识别显式隐藏的节点,隐藏子查询:

select menus.id, lft, rgt
from   menus
where  menus.visible = 0

第二步,获取所有被隐式隐藏的子树,子查询 hidden_​​all:

select menus.id
from
    (select id, lft, rgt
     from   menus
     where  menus.visible = 0) as hidden
inner join menus 
on (menus.lft between hidden.lft and hidden.rgt)

最后一步,检索除子查询 hidden_​​all 中的所有菜单选项。这可以通过外部连接或使用运算符 IN 来完成。使用最后一个选项:

select menus.*
from   menus
where  menus.lft between plft and prgt
       and not menus.id in (
    select    menus.id
    from      (select m.id, m.lft, m.rgt
               from   menus m
               where  m.visible = 0) as hidden
    inner join menus m
    on         (m.lft between hidden.lft and hidden.rgt)
    )

正如我之前提到的,它未经测试,您需要将 plft 和 prgt 替换为正确的值或将它们设为参数。

于 2013-03-26T22:04:32.790 回答
0

好吧,您是否尝试过添加:

and (nesty.visible <> 0 and parent.visible <> 0)
于 2013-03-26T18:18:23.577 回答