【问题标题】:How to fetch all siblings using SQL closure tables pattern (without subquery!)如何使用 SQL 闭包表模式获取所有兄弟姐妹(没有子查询!)
【发布时间】:2016-11-12 08:43:30
【问题描述】:

我正在尝试为一个简单的 Menu 模型实现闭包表模式,但在构建查询以查找当前节点的所有兄弟节点时遇到了一些困难没有子查询(例如,使用加入)。

有一个old question 与我的非常相似,但似乎没有答案(或者至少我不明白)。

以以下简化场景为例(不包括零深度记录):

menu:
+--+--------------+
| id | title      |
+--+--------------+
| 1  | Link 1     |  
| 2  | Link 1.1   | 
| 3  | Link 1.2   | 
| 4  | Link 1.3   | 
| 5  | Link 1.3.1 | 
| 6  | Link 1.3.2 |
+----+------------+

menu_closure:
+----------+------------+-------+
| ancestor | descendant | depth |
+----------+------------+-------+
| 1        | 2          | 1     |
| 1        | 3          | 1     |
| 1        | 4          | 1     |
| 1        | 5          | 2     |
| 1        | 6          | 2     |
| 4        | 5          | 1     |
| 4        | 6          | 1     |
+----------+------------+-------+

我想获取 Link 1.1 (id=2) -> Link 1.2 (id=3) 和 Link 1.3 (id=4) 的所有兄弟姐妹。

注意:我只知道目标 menu 记录的 id。

目前,我执行以下操作:

SELECT m.*
FROM menu AS m
LEFT JOIN menu_closure AS mc ON mc.descendant=m.id
WHERE m.id != 2
    AND mc.depth = 1
    AND mc.ancestor = (SELECT ancestor FROM menu_closure WHERE descendant=3 AND depth=1)

我正在考虑的另一个选择是首先获取 Link 1.1 的父级,然后通过排除 Link 1.1 的 id 来获取其子级,但我正在寻找一个只有 1 个查询的解决方案。

【问题讨论】:

  • 我无法确认任何问题,请参阅sqlfiddle.com/#!9/f671c6/1/0
  • 如果我理解正确,您的查询是“给我所有与 x 具有相同祖先和深度的项目”。不知何故,您必须查找直接祖先以链接 1.1 才能使其工作。当前查询的调整:您可以使用内部 JOIN(不是 LEFT)并且应该是 ... descendant=2 ... 如果您真的不想要子查询,您可以将 menu_closure 加入到自身中,如您链接到的示例中一样,但是对于下一个必须处理代码的人来说,子查询似乎更加透明。
  • @OlafDietsche 查询工作正常,但我正在寻找一个有连接的解决方案(没有子查询)
  • @Jerry 感谢您的建议,我会试一试。顺便提一句。我不想使用子查询的原因是因为我认为在大多数情况下使用 JOIN 比子查询更快,尤其是对于 MySql(如果我没记错的话)为每条记录执行子查询当它们在 WHERE 语句中时分开。
  • @RyanVincent 我不喜欢嵌套集合模式。就我而言,我有很多插入/删除。

标签: php mysql tree


【解决方案1】:

您首先检查ancestor

select *
from menu_closure a
where a.descendant = 2

然后拿起兄弟姐妹

select *
from menu_closure a
join menu_closure s on s.ancestor = a.ancestor
where a.descendant = 2

与“Link 1.1”深度相同

select *
from menu_closure a
join menu_closure s on s.ancestor = a.ancestor
where a.descendant = 2
    and s.depth = a.depth

添加菜单标题

select *
from menu_closure a
join menu_closure s on s.ancestor = a.ancestor
join menu m on m.id = s.descendant
where a.descendant = 2
    and s.depth = a.depth

并排除所有不需要的东西

select m.*
from menu_closure a
join menu_closure s on s.ancestor = a.ancestor
join menu m on m.id = s.descendant
where a.descendant = 2
    and s.depth = a.depth
    and m.id <> 2

最终sqlfiddle

【讨论】:

  • 感谢您的详细回答。
猜你喜欢
  • 1970-01-01
  • 2017-08-18
  • 1970-01-01
  • 2019-05-06
  • 1970-01-01
  • 1970-01-01
  • 2021-05-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多