Mysql 如何查询具有重复节点的闭包表中的路径?
在SQL中存储层次结构的一种非常有效的方法是使用某种“闭包表”。 编辑起来有点困难,占用了更多的空间,但如果您只对ID感兴趣,通常可以通过单个连接或单个查询递归地进行访问 此表将包含每个可能的祖先/后代关系的1条记录,以及实际表中每个项目的1条记录,其中Mysql 如何查询具有重复节点的闭包表中的路径?,mysql,sql,tree,Mysql,Sql,Tree,在SQL中存储层次结构的一种非常有效的方法是使用某种“闭包表”。 编辑起来有点困难,占用了更多的空间,但如果您只对ID感兴趣,通常可以通过单个连接或单个查询递归地进行访问 此表将包含每个可能的祖先/后代关系的1条记录,以及实际表中每个项目的1条记录,其中anc=des=id包含这些记录 对于此树: 1 2 4 7 3 5 6 1 2 3 5
anc=des=id
包含这些记录
对于此树:
1
2 4 7
3 5 6
1
2 3
5 4
6 6
我们的SQL表将包含:
+-----+-----+------+-------+
| anc | des | diff | depth |
+-----+-----+------+-------+
| 1 | 1 | 0 | 0 |
| 1 | 2 | 1 | 0 |
| 2 | 3 | 1 | 1 |
| 1 | 3 | 2 | 0 |
| 1 | 4 | 1 | 0 |
| 2 | 5 | 1 | 1 |
| 1 | 5 | 2 | 0 |
| 4 | 6 | 1 | 1 |
| 1 | 6 | 2 | 0 |
| 1 | 7 | 1 | 0 |
| 2 | 2 | 0 | 1 |
| 3 | 3 | 0 | 2 |
| 4 | 4 | 0 | 1 |
| 5 | 5 | 0 | 2 |
| 6 | 6 | 0 | 2 |
| 7 | 7 | 0 | 1 |
+-----+-----+------+-------+
然后,任务“获取节点5的所有祖先”,换句话说,“到节点5的路径”可以通过以下查询完成:
SELECT `anc` FROM `closure` WHERE `des` = 5
“获取节点1的所有后代”任务可以通过以下查询完成:
SELECT `des` FROM `closure` WHERE `anc` = 1
“获取节点1的所有直接子代”的操作如下:
SELECT `des` FROM `closure` WHERE `diff` = 1 AND `anc` = 1
最后,“获取所有根节点”如下所示:
SELECT `anc` FROM `closure` WHERE `depth` = 0 AND `anc` = `des`
这四项任务共同构成了从树中选择事物的最常用方式。
然而,在现实中,当对事物进行分类时,人们无法决定将事物放在何处。不可避免地,需要在树中的多个位置结束某些内容。这给工作带来了麻烦;其中两个天真的查询不再有效(no 1和no 2)
注意,为了防止堆栈溢出和递归问题,在示例中我们的图仍然是一种“树”;这里面没有循环
第一个问题是“获取所有子体”现在有重复的结果。这可以通过GROUP BY
子句解决
第二个,对我来说更难的,尚未解决的问题是第一个问题:现在有多个可能的路径到一个叶节点。让我们把这个问题分成两个可能令人满意的结果:
对于任意深度的树,是否有一种方法,在单个或固定数量的查询中使用单个或固定数量的联接,以获得以下任一结果:
规范路径
这是到特定叶节点的树表示中节点数最左侧最少的路径。请注意,树不一定像数据结构中的示例那样“排序”,因为节点是任意插入和删除的
所有路径
获取指向特定叶节点的所有可能路径
天真方法失败原因的一个示例:
以这棵树为例:
1
2 4 7
3 5 6
1
2 3
5 4
6 6
问“6的上升点是什么”应该有两个合乎逻辑的答案:
1-2-5-6和1-3-4-6
然而,使用天真的查询和排序,我们只能真正得到:
1-2-4-6或1-3-5-6
这两个路径实际上都不是有效的路径
在我读过的所有关于闭包表的教程中,都明确指出闭包表能够处理同一项出现在多个位置的层次结构,但实际上从未解释过如何正确地执行此操作,只是“留给读者”。然而,我在尝试时遇到了一些不寻常的问题