我在Postgres 9.1中表示一个图形(碰巧是双向的和循环的):
CREATE TABLE nodes (
id SERIAL PRIMARY KEY,
name text
);
CREATE TABLE edges (
id SERIAL PRIMARY KEY,
node1_id int REFERENCES nodes(id),
node2_id int REFERENCES nodes(id)
);
给定特定节点ID,想要检索该群集中的所有其他节点。我从“单个节点的路径”示例here开始,这是我得到的地方:
WITH RECURSIVE search_graph(id, path) AS (
SELECT id, ARRAY[id]
FROM nodes
UNION
SELECT e.node2_id, sg.path || e.node2_id
FROM search_graph sg
JOIN edges e
ON e.node1_id = sg.id
)
-- find all nodes connected to node 3
SELECT DISTINCT id FROM search_graph WHERE path @> ARRAY[3];
我无法弄清楚a)是否有更简单的方法来写这个,因为我不关心收集完整的path
,以及b)如何使它在两个方向上遍历({{每个边缘1}} - > node1
和node2
- > node2
。对一个好方法的任何亮点都会有所了解。谢谢!
答案 0 :(得分:2)
几点。
首先,您确实希望确保路径遍历不会进入循环。其次处理双方并不是太糟糕。最后,根据你正在做的事情,你可能想要以某种方式将where子句推入CTE,以减少生成每个可能的图形网络,然后选择你想要的那个。
遍历两个方向并不太难。我没有对此进行过测试,但应该可以使用以下内容:
WITH RECURSIVE search_graph(path, last_node1, last_node2) AS (
SELECT ARRAY[id], id, id
FROM nodes WHERE id = 3 -- start where we want to start!
UNION ALL
SELECT sg.path || e.node2_id || e.node1_id, e.node1_id, e.node2_id
FROM search_graph sg
JOIN edges e
ON (e.node1_id = sg.last_node2 AND NOT path @> array[e.node2_id])
OR (e.node2_id = sg.last_node1 AND NOT path @> array[e.node1_id])
)
-- Moved where clause to start of graph search
SELECT distinct unnest(path) FROM search_graph; -- duplicates possible
希望这有帮助。