如何在分层树中查找所有子节点

时间:2018-02-06 11:40:01

标签: mysql sql hierarchical-data

我有一张由fk parentId自引用的表。
给定一个id,我需要提取它的所有子节点 我知道图表只有三个级别:root,middleNode,leaf
所以我试过这个:

SELECT * 
FROM table AS root 
LEFT JOIN table AS middle
  ON middle.parentId = root.id
LEFT JOIN table AS leaf
  ON leaf.parentId = middle.id
WHERE root.id = 1

但是这样我每个节点都没有一行...

此外,此实现没有考虑到两件事:

  1. 它与3级结构相关联
  2. 如果我在树的中间搜索,它似乎不是最好的解决方案

2 个答案:

答案 0 :(得分:0)

对于3个级别,您可以使用

    SELECT * FROM 
-- root
(
SELECT * 
FROM your_table WHERE id = 1 
) as root
UNION ALL
-- level1
(
SELECT * FROM your_table WHERE parentId = 1 ) 
)
UNION ALL
-- level2
(
SELECT * FROM your_table WHERE parentId IN (SELECT id FROM your_table WHERE parentId = 1 ) 
)

但是对于深度,我建议您实施常用方法,例如嵌套集模型(需要添加额外的列),请take a look on this

答案 1 :(得分:0)

如果你想从你所在的位置沿着树走下去,你可以使用临时表来做到这一点。

CREATE TABLE tempTable (id int, parentid int);

INSERT INTO tempTable (id, parentid)
SELECT id, parentID FROM tree WHERE id = @input;
SET @LastCount=0;
SELECT @Count = COUNT(1) FROM tempTable;
WHILE @LastCount != @Count DO
    INSERT INTO tempTable (id, parentid)
    SELECT id,parentid from tree where id in (SELECT parentid FROM TempTable) AND ID NOT IN (SELECT id FROM TempTable);
    @LastCount = @Count;
    SELECT @Count = COUNT(1) FROM tempTable;
END WHILE;

SELECT * FROM tempTable;
DROP tempTable;

这将循环遍历,继续沿着层次结构向下移动,添加当前在表中具有父级的行,只要这些行不存在,并且在不添加新行时结束循环(最后一个循环)行计数=当前循环行计数)这样做的好处是根本不关心层次结构的大小,它可以是3级或30级,也不关心你从哪里开始,它总是下降一层。 / p>

如果您想要包含该节点的整个层次结构,您可以在层次结构中循环,直到找到没有父节点的层次结构(如果您在同一个表中有多个树,例如多个带有过道的仓库,并且每个仓库顶层):

SET @next = @input;
WHILE @next IS NOT NULL DO
 SET @topID = @next;
 SELECT @next = parentID FROM tree WHERE id=@topID;
END WHILE

CREATE TABLE tempTable (id int, parentid int);

INSERT INTO tempTable (id, parentid);
SELECT id, parentID FROM table WHERE id = @topID;
SET @LastCount=0;
SELECT @Count = COUNT(1) FROM tempTable;
WHILE @LastCount != @Count DO
    INSERT INTO tempTable (id, parentid)
    SELECT id,parentid from tree where id in (SELECT parentid FROM TempTable) AND ID NOT IN (SELECT id FROM TempTable);
    @LastCount = @Count;
    SELECT @Count = COUNT(1) FROM tempTable;
END WHILE;

SELECT * FROM tempTable;
DROP tempTable;

这将运行到树的顶部,然后逐级循环回来。任何一个都可以在while循环中使用一个计数器变量来查找从你开始的点开始的相对级别。

SQLFiddle不允许其中一些函数适用于MySQL,但我确实有一个MsSQL小提琴显示此函数有效 - MsSql Fiddle