【发布时间】:2014-02-26 05:50:00
【问题描述】:
我有一个图结构
Node(pid integer)
Neighbor(pid integer, pidn integer)
Node 是微不足道的,我应该说Neighbor 为每个节点存储其邻居列表。这是我正在测试的图表(Neighbor 关系的内容):
PID | PIDN
==========
1 | 2
1 | 3
2 | 1
2 | 3
2 | 4
2 | 5
3 | 1
3 | 2
4 | 2
4 | 6
5 | 2
6 | 4
我想得到一个节点的所有邻居的集合,度数小于一个固定的数,所以我执行以下查询:
WITH RECURSIVE search_graph(root, depth) AS (
SELECT n.pidn, 1
FROM node p, neighbor n
WHERE p.pid = n.pid
AND p.pid = 1
UNION
SELECT nxt.pidn, sg.depth + 1
FROM neighbor nxt, search_graph sg
WHERE sg.root = nxt.PID
AND sg.depth < 3
)
SELECT * FROM search_graph s;
起始节点为 1,最大深度为 3(以防错过)。我得到以下结果:
Node | Depth
============
2 | 1
3 | 1
1 | 2
3 | 2
4 | 2
5 | 2
2 | 2
2 | 3
3 | 3
1 | 3
4 | 3
5 | 3
6 | 3
因为它扩展了每个节点的所有子节点,包括访问过的子节点:
0 1
1 2 3
2 1 3 4 5 1 2
3 2 3 1 2 2 6 2 2 3 1 3 4 5
虽然我想排除访问过的孩子,但生成:
Node | Depth
============
2 | 1
3 | 1
4 | 2
5 | 2
6 | 3
我需要一种方法来将结果添加到 search_graph 仅当节点未被访问时。
【问题讨论】:
-
你考虑过看看
ltree吗?它可能会为您节省一些痛苦。另一种可能性可能是看看您是否可以以 GiST 索引可能能够处理的形式对这些数据进行建模。 -
在这上面花了几分钟,我不评价能够在递归 CTE 中做到这一点的机会。您需要一种方法来重新访问 search_graph 递归项(
EXISTS子查询、左反连接等)以排除已经访问过的节点,并且递归项上既不允许子查询也不允许左连接。您也不能使用数组轻松绕过它,因为递归术语中不允许使用聚合函数。我认为您必须使用递归 SQL 或 PL/PgSQL 函数或在客户端中编写此代码。 (详情:见已删除答案) -
好吧,我看不到已删除的答案...但我仍在寻找使用任何可能方式的解决方案... C/PgPLSQL/SQL ...
标签: sql postgresql recursion graph