问题
Consider that I have a table of points, each point has 2 coordinates. For example:
Source | Destination
1 | 2
2 | 3
3 | 7
5 | 7
9 | 12
I'd like to write a query in SQL that gives me the following:
- All the paths that these points make. Each path must have connected points, as in the next point's source coordinate is the same as the previous point's destination point.
- a path can't be cyclic.
For example, in the table above, running the query should return 3*paths:
- (1,2) (2,3) (3,7)
- (5,7)
- (9,12)
I thought about duplicating the points table, let's call them A and B, then set a condition:
SELECT source, destination
FROM A, B
WHERE A.source = B.destination
But I'm not sure about the answer and I'm almost sure it's not optimal.
回答1:
Use a recursive cte with an array[array[source, destination]] as an aggregation column:
with recursive cte(source, destination, path) as (
select source, destination, array[array[source, destination]]
from points
union all
select p.source, p.destination, path || array[p.source, p.destination]
from cte c
join points p on c.destination = p.source
where not array[array[p.source, p.destination]] <@ path
)
select distinct on (path[1:1]) path
from (
select distinct on (source, destination) *
from cte
order by source, destination, array_length(path, 1) desc
) s
order by path[1:1], array_length(path, 1) desc;
path
---------------------
{{1,2},{2,3},{3,7}}
{{5,7}}
{{9,12}}
(3 rows)
回答2:
with recursive
points(src, dst) as (values(1,2),(3,7),(2,3),(5,7),(9,12)),
result as (
select src, dst, array[src,dst] as point, 1 as n
from points p1
where not exists(select * from points p2 where p2.dst = p1.src)
union all
select result.src, points.dst, array[points.src, points.dst], n+1
from result join points on (result.dst = points.src)
)
select array_agg(point order by n) from result group by src;
来源:https://stackoverflow.com/questions/44140864/get-the-paths-from-a-database-of-points-in-sql