计算后代节点 [来自 MySQL 闭包模式]
Counting Descendant Nodes [from MySQL Closure Pattern]
我正在使用以下数据结构来表示数据的层次结构。
用户Table
+----+------+
| id | name |
+----+------+
| 1 | Bob |
| 2 | Sam |
| 3 | Joe |
| 4 | Kirk |
| 5 | Greg |
+----+------+
关系结束Table
+----------+------------+-------+
| 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):
- 鲍勃有一个儿子:山姆
- Sam 有两个儿子:Joe 和 Kirk。
- 乔没有儿子。
- 柯克有一个儿子:格雷格。
我正在从以下 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
这很好用。但是我还想return树下的子孙数量。到目前为止我能想到的最好的是:
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 |
+----+------+------------------+
问题(终于)
有没有比我现有的更好的求总数的方法?所有那些子 select 都是恶心的。
更新
当我看到这里时,我意识到对于这个例子我可能把事情简化了太多。我有两个 sub-selects 来做计数,因为我实际上有 3 个表:类别;物品; category_closure。在我的示例数据中,显然不需要双重嵌套子 select。在我的实际数据中有。希望这是有道理的。
您不需要子查询。您可以通过再次加入闭包 table 来获取每个 child 的后代数量,以找到其祖先是相应 child 的所有节点。然后使用 GROUP BY 这样你就可以得到每个 child.
的计数
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
我正在使用以下数据结构来表示数据的层次结构。
用户Table
+----+------+
| id | name |
+----+------+
| 1 | Bob |
| 2 | Sam |
| 3 | Joe |
| 4 | Kirk |
| 5 | Greg |
+----+------+
关系结束Table
+----------+------------+-------+
| 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):
- 鲍勃有一个儿子:山姆
- Sam 有两个儿子:Joe 和 Kirk。
- 乔没有儿子。
- 柯克有一个儿子:格雷格。
我正在从以下 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
这很好用。但是我还想return树下的子孙数量。到目前为止我能想到的最好的是:
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 |
+----+------+------------------+
问题(终于)
有没有比我现有的更好的求总数的方法?所有那些子 select 都是恶心的。
更新
当我看到这里时,我意识到对于这个例子我可能把事情简化了太多。我有两个 sub-selects 来做计数,因为我实际上有 3 个表:类别;物品; category_closure。在我的示例数据中,显然不需要双重嵌套子 select。在我的实际数据中有。希望这是有道理的。
您不需要子查询。您可以通过再次加入闭包 table 来获取每个 child 的后代数量,以找到其祖先是相应 child 的所有节点。然后使用 GROUP BY 这样你就可以得到每个 child.
的计数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