Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- We consider an oriented graph, with nodes ("+" : numbers) and arcs ( "-" : letters). Each arc is oriented from lowest node id to highest node id.
- We want to follow the graph from node 1 to node 10, propagating through all arcs, and keeping all arcs just once in our results.
- We want to keep the paths which we followed to each new visited arc.
- The graph :
- +1
- |
- |A
- B |
- 3+-----+2
- | |
- | |
- C| |E
- | |
- 4+-----+5
- D |
- |F
- |
- G |
- 7+----+6
- | |I
- |H |
- \----+8
- |
- | J
- |
- +9
- |
- |K
- |
- +10
- Expected result :
- A
- A-B
- A-E
- A-B-C
- A-E-F
- A-B-C-D
- A-E-F-G
- A-E-F-I
- A-E-F-G-H
- A-E-F-I-J
- A-E-F-I-J-K
- ( 11 rows )
- */
- /* create our graph table */
- drop table if exists graph;
- create table graph (
- id serial
- , node_start int
- , node_end int
- , nam varchar
- );
- /* insert the data corresponding to the graph above */
- insert into graph (node_start, node_end, nam)
- values ( 1, 2, 'A'), (2, 3, 'B'), (3, 4, 'C'), (4, 5, 'D'), (2, 5, 'E'), (5, 6, 'F'), (6, 7, 'G'), (7, 8, 'H'), (6, 8, 'I'), (8, 9, 'J'), (9, 10, 'K');
- /* check data */
- select * from graph;
- -- Follow the graph from 1 to 10 ( arc A to K )
- -- We only keep node identifiers and use union to deduplicate
- with recursive search_graph (id, node_end, nam) as (
- select g.id, g.node_end, g.nam from graph as g where nam = 'A'
- union
- select g.id, g.node_end, g.nam from search_graph as sg join graph as g on sg.node_end = g.node_start
- )
- select * from search_graph limit 100;
- -- 11 rows with visited nodes
- -- We now want to keep the paths to visited nodes
- with recursive search_graph (id, node_end, nam, path, depth) as (
- -- start data set : arc A
- select g.id, g.node_end, g.nam, ARRAY[g.nam] as path, 1 as depth from graph as g where nam = 'A'
- -- Recursive part
- -- Since the path is distinct for every new line, union does not deduplicate any longer
- -- we have to filter further on each recursion/iteration to deduplicate
- union
- select g.id, g.node_end, g.nam, sg.path || g.nam as path, depth + 1 as depth from search_graph as sg join graph as g on sg.node_end = g.node_start
- )
- select * from search_graph limit 100;
- -- This is the query we would expect to work
- with recursive search_graph (id, node_end, nam, path, depth) as (
- -- same data set as start : arc A
- select g.id, g.node_end, g.nam, ARRAY[g.nam] as path, 1 as depth from graph as g where nam = 'A'
- -- union does not deduplicate since we have the path
- union
- -- in the following line, PostgreSQL raises an error :
- -- ERROR: recursive reference to query "search_graph" must not appear within a subquery
- -- we could also use a "left join is null" structure, but PostgreSQL prevents the recursive CTE to be used in an outer join
- select g.id, g.node_end, g.nam, sg.path || g.nam as path, depth + 1 as depth from search_graph as sg join graph as g on sg.node_end = g.node_start and g.id not in (select id from search_graph)
- )
- select * from search_graph limit 100;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement