Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/56.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 如何查找树表示的层次结构路径_Mysql_Sql_Hierarchical Data - Fatal编程技术网

Mysql 如何查找树表示的层次结构路径

Mysql 如何查找树表示的层次结构路径,mysql,sql,hierarchical-data,Mysql,Sql,Hierarchical Data,我有一个树层次结构,它内置在一个表中,父节点id指向上一个根节点 我正在遍历所有根节点(root1、root2),并将root1和child1的路径设置为root1或root1/child1。为了找到child1的路径,我必须至少调用2次才能形成路径。有没有一种有效的方法来填充路径,因为我们处理的根节点和子节点数量非常多,嵌套深度为5-7级 create table foo (id, name, parent_id, path) insert into foo (1, "root1', null

我有一个树层次结构,它内置在一个表中,父节点id指向上一个根节点

我正在遍历所有根节点(root1、root2),并将root1和child1的路径设置为root1或root1/child1。为了找到child1的路径,我必须至少调用2次才能形成路径。有没有一种有效的方法来填充路径,因为我们处理的根节点和子节点数量非常多,嵌套深度为5-7级

create table foo (id, name, parent_id, path)
insert into foo (1, "root1', null, null)
insert into foo (2, "child1', 1, null)

root1 (path = null)
  child1 (path = root1)
    subchild1 (path = root1/child1)

root2
   child2
     subchild2

虽然严格来说不可能在单个调用中实现,但可以隐藏多个调用,但可以将它们放入从SQL调用的MySQL函数中,该函数返回父路径

虽然这可能比在脚本中执行效率更高,但我并不期望它有那么高的效率

如果“最大级别数”是固定的,则可以按如下方式使用连接:-

SELECT foo.id, foo.name, CONCAT_WS(',', d.name, c.name, b.name, a.name)
FROM foo
LEFT OUTER JOIN foo a ON foo.parent_id = a.id
LEFT OUTER JOIN foo b ON a.parent_id = b.id
LEFT OUTER JOIN foo c ON b.parent_id = c.id
LEFT OUTER JOIN foo d ON c.parent_id = d.id

尽管这会起作用,但它是相当严格的(即,如果级别的最大数量发生变化,则必须使用它来改变SQL的每一位),另外,如果级别数不是很小,它将变成一个无法读取的混乱状态。

您可以使用您在问题中提到的存储过程,因为嵌套可以达到7级深度

存储过程 为了检查实际记录,我们只打印了路径列中具有null值的普通记录

select * from foo
select * from foo
结果

| ID |         NAME | PARENT_ID |   PATH |
------------------------------------------
|  1 |        root1 |    (null) | (null) |
|  2 |       child1 |         1 | (null) |
|  3 |    subchild1 |         2 | (null) |
|  4 |       child2 |         1 | (null) |
|  5 |       child3 |         1 | (null) |
|  6 |    subchild2 |         4 | (null) |
|  7 | subsubchild1 |         6 | (null) |
call updatepath
| ID |         NAME | PARENT_ID |                   PATH |
----------------------------------------------------------
|  1 |        root1 |    (null) |                 (null) |
|  2 |       child1 |         1 |                  root1 |
|  3 |    subchild1 |         2 |           root1/child1 |
|  4 |       child2 |         1 |                  root1 |
|  5 |       child3 |         1 |                  root1 |
|  6 |    subchild2 |         4 |           root1/child2 |
|  7 | subsubchild1 |         6 | root1/child2/subchild2 |
调用过程

| ID |         NAME | PARENT_ID |   PATH |
------------------------------------------
|  1 |        root1 |    (null) | (null) |
|  2 |       child1 |         1 | (null) |
|  3 |    subchild1 |         2 | (null) |
|  4 |       child2 |         1 | (null) |
|  5 |       child3 |         1 | (null) |
|  6 |    subchild2 |         4 | (null) |
|  7 | subsubchild1 |         6 | (null) |
call updatepath
| ID |         NAME | PARENT_ID |                   PATH |
----------------------------------------------------------
|  1 |        root1 |    (null) |                 (null) |
|  2 |       child1 |         1 |                  root1 |
|  3 |    subchild1 |         2 |           root1/child1 |
|  4 |       child2 |         1 |                  root1 |
|  5 |       child3 |         1 |                  root1 |
|  6 |    subchild2 |         4 |           root1/child2 |
|  7 | subsubchild1 |         6 | root1/child2/subchild2 |
程序执行后的结果

| ID |         NAME | PARENT_ID |   PATH |
------------------------------------------
|  1 |        root1 |    (null) | (null) |
|  2 |       child1 |         1 | (null) |
|  3 |    subchild1 |         2 | (null) |
|  4 |       child2 |         1 | (null) |
|  5 |       child3 |         1 | (null) |
|  6 |    subchild2 |         4 | (null) |
|  7 | subsubchild1 |         6 | (null) |
call updatepath
| ID |         NAME | PARENT_ID |                   PATH |
----------------------------------------------------------
|  1 |        root1 |    (null) |                 (null) |
|  2 |       child1 |         1 |                  root1 |
|  3 |    subchild1 |         2 |           root1/child1 |
|  4 |       child2 |         1 |                  root1 |
|  5 |       child3 |         1 |                  root1 |
|  6 |    subchild2 |         4 |           root1/child2 |
|  7 | subsubchild1 |         6 | root1/child2/subchild2 |
结果

| ID |         NAME | PARENT_ID |   PATH |
------------------------------------------
|  1 |        root1 |    (null) | (null) |
|  2 |       child1 |         1 | (null) |
|  3 |    subchild1 |         2 | (null) |
|  4 |       child2 |         1 | (null) |
|  5 |       child3 |         1 | (null) |
|  6 |    subchild2 |         4 | (null) |
|  7 | subsubchild1 |         6 | (null) |
call updatepath
| ID |         NAME | PARENT_ID |                   PATH |
----------------------------------------------------------
|  1 |        root1 |    (null) |                 (null) |
|  2 |       child1 |         1 |                  root1 |
|  3 |    subchild1 |         2 |           root1/child1 |
|  4 |       child2 |         1 |                  root1 |
|  5 |       child3 |         1 |                  root1 |
|  6 |    subchild2 |         4 |           root1/child2 |
|  7 | subsubchild1 |         6 | root1/child2/subchild2 |

希望这有助于……

< P>你可以考虑将包含每个树根的所有元素添加到叶子中。(1999年起)介绍了一些理论背景

分层数据上的stackoverflow描述了许多替代方法。在那里,指向一个全面的参考书目,其中包括

闭包表的优点是查询效率高,并且解决方案不会影响当前的数据结构。您将需要使用闭包表扩展数据库,并在修改林时维护它


您可以用短路径指示表中的大量项。这使得闭包表性能与适当的索引保持近似线性。您还可以保留关闭表中每个节点的路径,以避免重新计算。该方法对每个操作都有固定数量的查询,并支持任何深度的层次结构。

我非常喜欢修改的前序树遍历。它允许您在单个查询中获得整个树继承权。以下是详细的教程:


如果您对MPTT有任何疑问,请告诉我,我很乐意为您提供帮助

您应该使用嵌套集模型

如果从头开始设计,并且数据相当静态,那么这可能是最好的解决方案。在现有数据库上实现它有点问题,而且(以我的经验)如果有任何合理的插入和删除量,就会导致很大的开销。对于这样一个好的答案+1。我很抱歉在这里发表评论,但我需要你的帮助来解决类似的问题。谢谢。有趣的解决方案。在循环中使用SELECT ROW_COUNT()来获取更新的记录计数可能比获取路径仍然为空的行数更有效(然后可以更改循环以检查更新的记录数是否大于0)。此外,如果存在一个父id不存在的子记录,这将防止出现无休止的循环。谢谢..它对我来说很有吸引力…但我面临的一个问题是,当我从java应用程序调用此过程时..它会导致锁和过程不稳定地运行,导致我杀死应用程序。检查innodb引擎状态告诉我正在while循环中等待更新查询…你知道它为什么会在应用程序事务中运行吗,该事务只是调用这个进程来回答我自己的评论..我的进程在从java应用程序运行时进入了一个infinte循环。原因是我使用了select rowcount()查找更新的计数,并在while循环中使用相同的计数。现在更新中的where子句是“where b.path不为null且a.parent_id=b.id”,尽管我可以从workkbench中看到,如果要更新的列相同,则显示0行已更改,找到了5,但在从java应用程序运行时,它始终找到了5,并导致它在无限循环中运行。我需要修改update语句以添加“a.path为null”。更多详情请访问