I have a graph structure
Node(pid integer)
Neighbor(pid integer, pidn integer)
Node
is trivial, and I should say that Neighbor
stores for every node its list of Neighbors. This is the graph I am testing (contents of the Neighbor
relation):
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
I want to get the set of all neighbors of a node, with degree less than a fixed number, so I execute the following query:
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;
The starting node is 1, and the maximal depth is 3 (in case you missed them). I get the following result:
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
because it expands all the children of each node, including visited children:
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
While it I want to exclude visited children, producing:
Node | Depth
============
2 | 1
3 | 1
4 | 2
5 | 2
6 | 3
I need a method to add results to search_graph ONLY IF the node was not visited.
ltree
? It might save you a bit of pain. Another possibility may be to see if you can model this data in a form that a GiST index might be able to handle.EXISTS
subquery, left anti-join, etc) to exclude already-visited nodes, and neither subqueries nor left joins are permitted on the recursive term. Nor can you use arrays to get around it easily because aggregate functions are not permitted in the recursive term. I think you'll have to write this with recursive SQL or PL/PgSQL functions, or in the client. (Details: see deleted answer)