Mysql 如何查询具有重复节点的闭包表中的路径?

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

在SQL中存储层次结构的一种非常有效的方法是使用某种“闭包表”。 编辑起来有点困难,占用了更多的空间,但如果您只对ID感兴趣,通常可以通过单个连接或单个查询递归地进行访问

此表将包含每个可能的祖先/后代关系的1条记录,以及实际表中每个项目的1条记录,其中
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

这两个路径实际上都不是有效的路径

在我读过的所有关于闭包表的教程中,都明确指出闭包表能够处理同一项出现在多个位置的层次结构,但实际上从未解释过如何正确地执行此操作,只是“留给读者”。然而,我在尝试时遇到了一些不寻常的问题