如何找到层次树中的所有子节点

how to find all the child nodes in hierarchical tree

我有一个 table 由 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. 在我看来,如果我在树的中间搜索,这似乎不是最好的解决方案

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

如果你想从你所在的点向下走,你可以使用临时 table。

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;

这将一遍又一遍地循环,在层次结构中进一步向下,添加当前在 table 中具有父级的行,只要这些行还不存在,并在添加时结束循环没有新行(最后一个循环行数 = 当前循环行数)这样做的好处是根本不关心层次结构的大小,它可以是 3 级或 30 级,也不关心你从哪里开始,它总是再降一级。

如果您想要包含该节点的整个层次结构,您可以沿着层次结构向上循环,直到找到没有父节点的节点(如果您在同一 table 中有多个树,比如多个仓库过道、货架、各仓库顶层):

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 fiddle 显示此函数有效 - MsSql Fiddle