我有一个表使用枚举路径表示层次结构的表:
id | name | path
-----+-------+-------
1 | Bob | 1
2 | Joe | 2
3 | Kyle | 2/3
4 | Sarah | 2/4
5 | Jim | 5
6 | Steve | 5/6
7 | Adam | 5/7
8 | Frank | 5/7/8
9 | Sue | 5/7/9
我需要一个查询,它返回给定记录的直接子项,并为每个子项返回其下所有子记录的计数。
例如,针对Jim(id = 5)的查询应返回以下集合:
id | name | path | subrecords
-----+-------+-------+------------
6 | Steve | 5/6 | 0
7 | Adam | 5/7 | 2
如果我这样做:
select did, name, path, SUBSTRING(path FROM '5\/[^\/]*$') as child_path from items where path ~ '5\/.*';
我参与其中的一部分...
did | name | path | child_path
-----+-------+-------+---------
6 | Steve | 5/6 | 5/6
7 | Adam | 5/7 | 5/7
8 | Frank | 5/7/8 |
9 | Sue | 5/7/9 |
...但是记录8和9需要汇总为7以下的计数。
我试过了:
select SUBSTRING(path FROM '5\/[^\/]*$') as child_path, COUNT(id) as count from items where path ~ '5\/.*' GROUP BY child_path;
哪个让我:
child_path | count
----------+-------
| 2
5/7 | 1
5/6 | 1
不。
我怎么能实现这个目标?
答案 0 :(得分:2)
在我看来,这样做了。
SELECT i.id,
i.name,
i.path,
count(ii.id) AS cnt
FROM items i
LEFT OUTER JOIN items ii
ON ii.id != i.id AND ii.path LIKE i.path || '%'
WHERE i.path ~ '5\/[^\/]*$'
GROUP BY i.id,
i.name,
i.path;
答案 1 :(得分:2)
我认为你可以在没有自我加入的情况下做到这一点。
您可以使用以下表达式选择给定节点的所有后代:path like '5' || '/' || id || '%'
。然后,您可以通过选择最多5个子字符串和下一个id:
select left(path, length('5'||'/') + position('/' in split_part(path||'/', '5'||'/', 2)) - 1) as child,
count(*) - 1 as numdescendants
from items
where path like '5' || '/' || '%'
group by child;
count(*)
计算特定孩子的后代数,包括该孩子。因此,- 1
来获取他们后代的数量。
这应该有效,因此您可以用任何路径替换'5'
。