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

时间:2013-03-23 06:23:12

标签: mysql sql hierarchical-data

我有一个树形层次结构,它将内置于一个表中,其中parent_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

5 个答案:

答案 0 :(得分:11)

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

存储过程

CREATE PROCEDURE updatePath()
BEGIN
declare cnt, n int;
    select count(*) into n from foo where parent_id is null;
    update foo a, foo b set a.path = b.name where b.parent_id is null and a.parent_id = b.id;
    select count(*) into cnt from foo where path is null;
    while cnt > n do
        update foo a, foo b set a.path = concat(b.path, '/', b.name) where b.path is not null and a.parent_id = b.id;
        select count(*) into cnt from foo where path is null;
    end while;
END//

为了检查实际记录,我们刚刚在路径列

中打印了具有空值的普通记录
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

程序执行后的结果

select * from foo

<强>结果:

| 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 |

SQLFIDDLE

希望这会有所帮助......

答案 1 :(得分:1)

我非常喜欢Modified Preorder Tree Traversal。它允许您在单个查询中获得整个树层次结构。这是一个详细的教程:http://www.sitepoint.com/hierarchical-data-database-2/

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

答案 2 :(得分:0)

虽然在单个调用中不是严格可行的,但您可以隐藏多个调用,但将它们放入您从SQL调用的MySQL函数中,该函数将返回父路径。

虽然这可能比在脚本中执行它更有效,但我不希望它有效。

如果最大级别数被修复,您可以按如下方式使用JOIN: -

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的每一位),再加上如果级别的数量不是很小,它将变得不可读混乱。

答案 3 :(得分:0)

您可以考虑将包含每个树根的所有closure tablepaths添加到树叶中。 Maintaining the transitive closure of graphs in SQL(自1999年起)描述了一些理论背景。

Hierarchical data上的stackoverflow review question描述了许多替代方法。在那里,Tegiri Nenashi指向包含Hierarchical data in RDBMSs的综合参考书目。

Closure表的优势在于查询是高效的,并且解决方案不会影响您当前的数据结构。您需要使用闭包表进行扩展,并在修改林时对其进行维护。

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

答案 4 :(得分:0)

您应该使用嵌套集模型 http://en.wikipedia.org/wiki/Nested_set_model