【问题标题】:how to find all the child nodes in hierarchical tree如何在分层树中找到所有子节点
【发布时间】:2018-02-06 11:40:01
【问题描述】:

我有一个由 fk parentId 自引用的表。
给定一个给定的 id,我需要提取它的所有子节点。
我知道该图恰好具有三个级别:根、中间节点、叶
所以我尝试了这个:

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. 在我看来,如果我在树的中间进行搜索,这似乎不是最佳解决方案

【问题讨论】:

  • 如果您有任何问题,请将其包含在问题中。样本数据和期望的结果也有帮助。
  • 如果树的最大深度很小,比如 4-5,那么 LEFT JOIN 需要的次数。
  • 查找递归 CTE
  • 您是要查找层次结构中的所有节点,还是仅查找从起点向下的所有节点?
  • @SalmanA 他不想要left join 他真正想要的是union

标签: mysql sql hierarchical-data


【解决方案1】:

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

【讨论】:

  • 这不符合问题2,该选项要求您从树的顶部开始。
  • 你试过吗,把3个your_table改成table你的情况? (在我的,它首先显示root,然后是level1,然后是level2)。或者我不太明白你说的选项要求你从树的顶部开始是什么意思
  • 我可能误解了这个问题,如果 OP 只想从那一点开始你的工作,尽管你正在做一些不需要的工作 SELECT id FROM your_table WHERE id = 1 是多余的,你正在选择你提供的 where 子句。
【解决方案2】:

如果你想从你所在的点向下走,你可以使用临时表来做到这一点。

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 级,也不关心你从哪里开始,它总是再往下一层。

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

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

【讨论】:

  • 我承认我不是 mysql 专家,而且 sqlfiddle 不喜欢在 mysql 上运行这种解决方案,所以我没有对其进行测试,但我确实将它从工作的 mssql 转换为 mysql 语法解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-08-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-06
  • 1970-01-01
相关资源
最近更新 更多