Postgresql 如何从邻接列表中获取后代数组?
我有下表和数据Postgresql 如何从邻接列表中获取后代数组?,postgresql,Postgresql,我有下表和数据 CREATE TABLE relationships (a TEXT, b TEXT); CREATE TABLE nodes(n TEXT); INSERT INTO relationships(a, b) VALUES ('1', '2'), ('1', '3'), ('1', '4'), ('1', '5'), ('2', '6'), ('2', '7'), ('2', '8'), ('3', '9'); INSERT INTO nodes(n) VAL
CREATE TABLE relationships (a TEXT, b TEXT);
CREATE TABLE nodes(n TEXT);
INSERT INTO relationships(a, b) VALUES
('1', '2'),
('1', '3'),
('1', '4'),
('1', '5'),
('2', '6'),
('2', '7'),
('2', '8'),
('3', '9');
INSERT INTO nodes(n) VALUES ('1'), ('2'), ('3'), ('4'), ('5'), ('6'), ('7'), ('8'), ('9'), ('10');
我想要输出
n | children
1 | ['2', '3', '4', '5', '6', '7', '8', '9']
2 | ['6', '7', '8', '9']
3 | ['9']
4 | []
5 | []
6 | []
7 | []
8 | []
9 | []
10 | []
我试图将与RECURSIVE
结合使用,但仍停留在如何将参数传递到CTE上
WITH RECURSIVE traverse(n) AS (
SELECT *
FROM relationships
WHERE a = n --- not sure how to pass data to here
UNION ALL
...
)
WITH basic_cte AS (
SELECT a1.n as n,
(SELECT COALESCE(json_agg(temp), '[]')
FROM (
(SELECT * FROM traverse(a1.a))
) as temp
) as children
FROM nodes as a1
)
SELECT *
FROM basic_cte;
注意:这将忽略所有空的子项。您可以像中一样添加左连接以获得该功能 除非转向存储过程等,否则无法将参数真正传递到CTE中。CTE是一个单独的表,需要包含您可能希望从中使用的所有行 假设一个相当好的图(没有重复的边,没有循环),下面这样的代码应该满足您的要求
- 递归查询的基本情况是获取可能是父节点的所有节点的所有1级子节点(子节点)
- 递归步骤沿树向下遍历第二级、第三级等
- 一旦我们有了所有的父-子元组,我们就可以根据需要聚合数据
要获取所有节点的子节点的列表,需要向nodes表进行左联接
with recursive rels as (
select a,b, a as root
from relationships
union all
select c.*, r.root
from relationships c
join rels r on r.b = c.a
)
select n.n, array_agg(r.b) filter (where r.b is not null)
from nodes n
left join rels r on r.root = n.n
group by n.n
order by n.n;
@汉斯马斯格雷夫:是的correct@a_horse_with_no_name我会改正的谢谢你非常感谢!这段代码提供了很多洞察,但它不会填充空的子项(我可以通过左连接实现这一点)哦,感谢您指出这一点!我应该更加注意期望的输出;)因为它似乎对你有一些价值,所以我将保持原样,只参考另一个答案。嗨,我刚刚在CTE上运行了解释分析。知道为什么估计的行数这么高吗<代码>(成本=21776.23..29537.83行=388080宽度=64)(实际时间=0.053..0.148行=12个循环=1)实际行数为12,但估计行数约为380k?我不知道这是从哪里来的,不运行查询就准确地估计递归行数通常是一个不可能的问题(即使对于非常简单的查询),因此postgres的错误在于根本不尝试。如果您有关于正在运行的查询的更多信息,您可能会得到一些帮助,例如帮助查询规划器解决问题代码>
真空(分析)关系代码>计划现在看起来不错:)谢谢!
with recursive rels as (
select a,b, a as root
from relationships
union all
select c.*, r.root
from relationships c
join rels r on r.b = c.a
)
select n.n, array_agg(r.b) filter (where r.b is not null)
from nodes n
left join rels r on r.root = n.n
group by n.n
order by n.n;