计算子代节点[来自MySQL闭包模式]

计算子代节点[来自MySQL闭包模式],mysql,hierarchical-data,Mysql,Hierarchical Data,我使用以下数据结构来表示数据的层次结构 用户表 +----+------+ | id | name | +----+------+ | 1 | Bob | | 2 | Sam | | 3 | Joe | | 4 | Kirk | | 5 | Greg | +----+------+ +----------+------------+-------+ | ancestor | descendant | depth | +----------+------------+------

我使用以下数据结构来表示数据的层次结构

用户表

+----+------+
| id | name |
+----+------+
|  1 | Bob  |
|  2 | Sam  |
|  3 | Joe  |
|  4 | Kirk |
|  5 | Greg |
+----+------+
+----------+------------+-------+
| ancestor | descendant | depth |
+----------+------------+-------+
|        1 |          1 |     0 |
|        1 |          2 |     1 |
|        1 |          3 |     2 |
|        1 |          4 |     2 |
|        1 |          5 |     3 |
|        2 |          2 |     0 |
|        2 |          3 |     1 |
|        2 |          4 |     1 |
|        2 |          5 |     2 |
|        3 |          3 |     0 |
|        4 |          4 |     0 |
|        4 |          5 |     1 |
|        5 |          5 |     0 |
+----------+------------+-------+
关系结束表

+----+------+
| id | name |
+----+------+
|  1 | Bob  |
|  2 | Sam  |
|  3 | Joe  |
|  4 | Kirk |
|  5 | Greg |
+----+------+
+----------+------------+-------+
| ancestor | descendant | depth |
+----------+------------+-------+
|        1 |          1 |     0 |
|        1 |          2 |     1 |
|        1 |          3 |     2 |
|        1 |          4 |     2 |
|        1 |          5 |     3 |
|        2 |          2 |     0 |
|        2 |          3 |     1 |
|        2 |          4 |     1 |
|        2 |          5 |     2 |
|        3 |          3 |     0 |
|        4 |          4 |     0 |
|        4 |          5 |     1 |
|        5 |          5 |     0 |
+----------+------------+-------+
以上数据代表以下内容(英语ese):

  • 鲍勃有一个儿子:萨姆
  • 萨姆有两个儿子:乔和柯克
  • 乔没有儿子
  • 柯克有一个儿子:格雷格
  • 我从以下SQL获取给定用户的儿子:

    SELECT u.*
    FROM closure AS c
        INNER JOIN `user` AS u ON (u.id = c.descendant)
    WHERE c.ancestor = 1 AND c.depth = 1
    
    这个很好用。但我也想把一路下来的后代数量还给大家。到目前为止,我能想到的最好的方法是:

    SELECT 
        u.*,
        (
            SELECT COUNT(id) FROM `user` WHERE id IN (
                SELECT descendant FROM closure 
                WHERE ancestor = c.descendant
            )
        ) AS descendant_count
    FROM closure AS c
        INNER JOIN `user` AS u ON (u.id = c.descendant)
    WHERE c.ancestor = 1 AND c.depth = 1
    
    上述查询的预期输出为:

    +----+------+------------------+
    | id | name | descendant_count |
    +----+------+------------------+
    |  2 | Sam  |                3 |
    +----+------+------------------+
    
    问题(最后)

    有没有比我现有的更好的方法来计算总数?所有这些子选择都是粗略的

    更新

    +----+------+
    | id | name |
    +----+------+
    |  1 | Bob  |
    |  2 | Sam  |
    |  3 | Joe  |
    |  4 | Kirk |
    |  5 | Greg |
    +----+------+
    
    +----------+------------+-------+
    | ancestor | descendant | depth |
    +----------+------------+-------+
    |        1 |          1 |     0 |
    |        1 |          2 |     1 |
    |        1 |          3 |     2 |
    |        1 |          4 |     2 |
    |        1 |          5 |     3 |
    |        2 |          2 |     0 |
    |        2 |          3 |     1 |
    |        2 |          4 |     1 |
    |        2 |          5 |     2 |
    |        3 |          3 |     0 |
    |        4 |          4 |     0 |
    |        4 |          5 |     1 |
    |        5 |          5 |     0 |
    +----------+------------+-------+
    

    当我看到这一点时,我意识到,对于这个例子来说,我可能把事情简化得太多了。我有两个子选择做计数,因为我实际上有3个表:类别;项目;U类关闭。在我的示例数据中,显然不需要双嵌套子选择。在我的实际数据中有。希望这是有意义的。

    您不需要子查询。您可以通过再次加入闭包表来获得每个子节点的子节点数,以查找其祖先为相应子节点的所有节点。然后使用GROUPBY,这样就可以得到每个孩子的计数

    SELECT 
        u.*,
        COUNT(*) AS descendant_count
    FROM closure AS c
        INNER JOIN `user` AS u ON (u.id = c.descendant)
        INNER JOIN closure AS d ON (c.descendant = d.ancestor)
    WHERE c.ancestor = 1 AND c.depth = 1
    GROUP BY c.descendant
    

    您不需要子查询。您可以通过再次加入闭包表来获得每个子节点的子节点数,以查找其祖先为相应子节点的所有节点。然后使用GROUPBY,这样就可以得到每个孩子的计数

    SELECT 
        u.*,
        COUNT(*) AS descendant_count
    FROM closure AS c
        INNER JOIN `user` AS u ON (u.id = c.descendant)
        INNER JOIN closure AS d ON (c.descendant = d.ancestor)
    WHERE c.ancestor = 1 AND c.depth = 1
    GROUP BY c.descendant
    

    您不需要子查询。您可以通过再次加入闭包表来获得每个子节点的子节点数,以查找其祖先为相应子节点的所有节点。然后使用GROUPBY,这样就可以得到每个孩子的计数

    SELECT 
        u.*,
        COUNT(*) AS descendant_count
    FROM closure AS c
        INNER JOIN `user` AS u ON (u.id = c.descendant)
        INNER JOIN closure AS d ON (c.descendant = d.ancestor)
    WHERE c.ancestor = 1 AND c.depth = 1
    GROUP BY c.descendant
    

    您不需要子查询。您可以通过再次加入闭包表来获得每个子节点的子节点数,以查找其祖先为相应子节点的所有节点。然后使用GROUPBY,这样就可以得到每个孩子的计数

    SELECT 
        u.*,
        COUNT(*) AS descendant_count
    FROM closure AS c
        INNER JOIN `user` AS u ON (u.id = c.descendant)
        INNER JOIN closure AS d ON (c.descendant = d.ancestor)
    WHERE c.ancestor = 1 AND c.depth = 1
    GROUP BY c.descendant
    

    {拍头}。这么简单。谢谢你,比尔。昨晚我绊倒了自己,把事情弄得太难了。感谢你的回答。(旁注——我刚刚读了这篇文章,它太棒了。我正在窃取最上面的子弹清单){Head Slap}。这么简单。谢谢你,比尔。昨晚我绊倒了自己,把事情弄得太难了。感谢你的回答。(旁注——我刚刚读了这篇文章,它太棒了。我正在窃取最上面的子弹清单){Head Slap}。这么简单。谢谢你,比尔。昨晚我绊倒了自己,把事情弄得太难了。感谢你的回答。(旁注——我刚刚读了这篇文章,它太棒了。我正在窃取最上面的子弹清单){Head Slap}。这么简单。谢谢你,比尔。昨晚我绊倒了自己,把事情弄得太难了。感谢你的回答。(旁注——我刚刚读了这篇文章,它太棒了。我正在窃取顶部的子弹清单)