我是PostgreSQL中WITH RECURSIVE
的新手。我有一个相当标准的递归查询,它遵循一个邻接列表。如果我有,例如:
它产生:
1
1,2
1,2,3
1,2,3,4
1,2,3,5
1,2,3,5,6
字符串
我想要的是:
1,2,3,4
1,2,3,5,6
型
但我不知道如何在Postgres中做到这一点。这似乎是“选择最长的路径”或“选择不包含在另一个路径中的路径”。我可能可以看到如何在其自身上使用join来做到这一点,但这似乎效率很低。
示例查询是:
WITH RECURSIVE search_graph(id, link, data, depth, path, cycle) AS (
SELECT g.id, g.link, g.data, 1, ARRAY[g.id], false
FROM graph g
UNION ALL
SELECT g.id, g.link, g.data, sg.depth + 1, path || g.id, g.id = ANY(path)
FROM graph g, search_graph sg
WHERE g.id = sg.link AND NOT cycle
)
SELECT * FROM search_graph;
型
3条答案
按热度按时间ykejflvf1#
您已经有了一个触手可及的
cycle
解决方案,只需在最后添加一个 predicate 。但是调整你的break条件一个级别,目前你追加了一个节点太多:
字符串
cycle
的初始化条件是(link = id)
,以捕获快捷方式循环。如果您有CHECK
约束来禁止表中的快捷方式循环,则不需要。link IS NULL
终止,并且在同一个表中有一个从link
到id
的FK约束。确切的实现取决于缺少的细节。如果link
实际上不是一个链接(没有引用完整性),你需要适应...cqoc49vn2#
只需将extra子句添加到最终查询中,如:
字符串
请注意:
not exists(...)
-子句试图连接与递归联合的第二个 * 分支 * 完全相同的记录。3mpgtkmj3#
我不确定这是否应该被认为是丑陋的连接解决方案。
字符串
因此,诀窍是使用
terminated
列通过使用LEFT OUTER JOIN
,然后只选择终止路径。