【问题标题】:Calculate depth in a parent-child model in MySQL在 MySQL 中计算父子模型的深度
【发布时间】:2009-07-28 18:27:41
【问题描述】:

MySQL下如何计算父子模型中节点的深度?

除其他外,我需要在列表中创建缩进的深度(使用 PHP 编码)。

【问题讨论】:

  • 我刚刚看到你的另一个问题:在嵌套集模型中移动节点,看起来你得到了一些非常矛盾的答案,所以我可以理解你的沮丧:-) 在嵌套中移动节点设置模型实际上非常简单(尽管取决于您的表大小,它可能很昂贵)。如果您仍然对此感兴趣,请告诉我,我可以添加答案和解释。
  • 哈哈没错,我对此感到非常沮丧。大约一周前我找到了一个我认为应该可行的解决方案,但尚未实施。但是对于我的目的,嵌套集不能很好地工作,因为许多不同的用户可能会每天进行许多更新,这意味着表中有很多行。出于这个原因,我会给这个邻接列表模型一个镜头,它可以安全地移动一个节点。 竖起大拇指
  • 祝您实施顺利。我已经更新了我的答案以反映邻接列表模型。

标签: mysql parent-child hierarchy depth


【解决方案1】:

这取决于数据库中层次结构的实际实现。如果您使用嵌套集模型 (http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/),您可以通过单选检索完整的父子路径。

更新:好的,既然你要使用邻接列表模型,我建议将节点级别存储在表中。它不仅会在一次查询中为您提供节点深度,而且还允许您在一次查询中检索到该节点的整个路径(尽管必须动态生成该查询):

SELECT n1.name AS lvl1, n2.name as lvl2, n3.name as lvl3, ..., nN.name as lvlN
  FROM nodes AS n1
  JOIN nodes AS n2 ON n2.parent_id = n1.id
  JOIN nodes AS n3 ON n3.parent_id = n2.id
  ...
  JOIN nodes AS nN ON nN.parent_id = n(N-1).id
WHERE nN.id = myChildNode;

由于您知道您的节点位于 N 级,因此不需要左连接,并且给定 id / parent_id 上的适当索引,这应该相当快。
这种方法的缺点是您必须在节点移动期间保持节点级别更新,但这应该相当简单和快速,因为您只会对节点本身及其子节点执行此操作 - 而不是对表的大部分你会使用嵌套集。

【讨论】:

  • 是的,我使用过嵌套集并且知道如何计算那里的深度,但现在我需要来自父子模型的深度(显然只有列 id 和父列),而不是嵌套集。
  • 顺便说一下,我感兴趣的是深度(整数),而不是路径。
  • 你说的是邻接表模型。不幸的是,这远非理想 - 您需要 N 次选择才能为第 N 级节点的深度提供资金。
  • 好的,所以您建议我在名为 depth 的表中添加另一列?但是我看不到您在示例中使用它。在这种情况下,它会安全吗?如果可能的话,我更喜欢一个不会​​更改多行的快速系统。 :)
  • 在我的示例中,深度为 N,您正在生成具有 N 个连接的单个查询。在事先不知道深度的情况下,您将不得不执行 N 个查询来做同样的事情。如果您碰巧知道整个层次结构的最大可能深度(例如,它不能超过 X 级别),另一个可能的折衷方案是使用 X 外连接重写上述查询。它的性能不会那么好,但您不必为每个节点保持节点级别。
【解决方案2】:

这可能是一个老问题,但我只想让其他人知道我在几个月前找到了解决方案。我最近确实在这里写过:http://en.someotherdeveloper.com/articles/adjacency-list-model-with-depth-calculation/

【讨论】:

    【解决方案3】:

    如果您只想复制粘贴,这是我的示例。 我有带有 ID 和 PARENT_ID 文件的表项目。

    DELIMITER $$
    DROP FUNCTION IF EXISTS `getDepth` $$
    CREATE FUNCTION `getDepth` (project_id INT) RETURNS int
    BEGIN
        DECLARE depth INT;
        SET depth=1;
    
        WHILE project_id > 0 DO
            SELECT IFNULL(parent_id,-1) 
            INTO project_id 
            FROM ( SELECT parent_id FROM Projects WHERE id = project_id) t;
    
            IF project_id > 0 THEN
                SET depth = depth + 1;
            END IF;
    
        END WHILE;
    
        RETURN depth;
    
    END $$
    DELIMITER ;
    

    【讨论】:

      猜你喜欢
      • 2016-10-14
      • 1970-01-01
      • 1970-01-01
      • 2011-06-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-04
      • 2017-08-21
      相关资源
      最近更新 更多