spatial data query - sql

I have the following query which does a self join with a table and outputs all the points of intersections between lines.
insert into road_intersection
select nextval('road_intersection_id_seq'), a.road_id, b.road_id, st_intersection(a.road, b.road), st_centroid(st_intersection(a.road, b.road))
from polygon_road a, polygon_road b
where st_intersects(a.road, b.road) AND a.road_id!=b.road_id
BUT it outputs duplicate values for each point of intersection since it computes the point of intersection for each road. EG:
70;71;POINT_OF_INTERSECTION
71;70;POINT_OF_INTERSECTION
70 AND 71 are both id values of two distinct roads. As you can see the point of intersection has been computed twice for the same two roads.
Any suggestions how i can solve this issue and only one point of intersection would be computed?

Try something like:
select nextval('road_intersection_id_seq'),
a.road_id,
b.road_id,
st_intersection(a.road, b.road),
st_centroid(st_intersection(a.road, b.road))
from polygon_road a, polygon_road b
where st_intersects(a.road, b.road)
--AND a.road_id!=b.road_id --not needed any more
AND a.road_id < b.road_id
It will leave only one of the intersections (the one, where the first road has smaller id)

Related

PostGIS find linestrings that are connected

Hi i am trying to get all linestrings that are close to the nodes of other linestring
I tried:
SELECT *
FROM lines p
JOIN lines ps ON( ST_Buffer(p.geom, 0.01) && ps.geom
AND ST_Intersects(st_buffet(p.geom, 0.01), ps.geom))
But I also get lines that intersects.
There is function ST_Touches() however i can't figure out how can I add some tolerance. Maybe there is a way to make buffer over linestring nodes?
You would need to extract the nodes using st_dumpPoints, then you can join the line to these points. It is better to use st_dwithin rather than an inexact buffer.
The query would be similar to
SELECT *
FROM lines p
JOIN
(SELECT *, (ST_DumpPoints(geom)).geom
FROM lines ps) as pts
ON st_dwithin(p.geom, ps.geom, 0.1);
You might want to select something else than *, as you would get 3 geometries per row (1st line, 2 line, node of contact)
PS: regarding st_touch, the two lines can still touch each others between 2 vertices.

How to find the points that did not intersect with STIntersect using SQL Server

I performed STInteract using two tables and the intersections of points onto a given polygon. I have converted all the tables to have geometries for all. I am having a problem writing the query for this. I am trying to look for the points that did not intersect.
These are my two table
PO_Database = contains the points
POLY_Database = Polygon of interest
This is my script:
SELECT GEOM
FROM [dbo].[PO_Database] as PO
JOIN [dbo].[POLY_Database] as p ON hwy.GEOM.STIntersects(p.NEATCELL) = 1
I tried changing the value from 1 to 0 but I get repeating values of the geometry for when the query is run with 0. How do I write the query to give me the names of the points that did not intersect with the polygon. Also is there a way to do checks if the intersects where done right.
If you get repeating values, you probably have multiple rows in the POLY_Database table. If you want to find the points that do not intersect any of those polygons, try this query:
SELECT GEOM
FROM [dbo].[PO_Database] as PO
WHERE NOT EXISTS (
SELECT * FROM [dbo].[POLY_Database] as p
WHERE hwy.GEOM.STIntersects(p.NEATCELL) = 1
)

Finding the pair of points whose distance from each other is maximal

I have a very small database which includes 6 points, with those columns id, the_geom, descr. And my aim to write a PL/pgSQL function which finds the the pair of points whose distance from each other is maximal. As an output, I would like to show the id or descr of two points and also the distance between them.
I have tried to do a function with returns table but setof text would be better solution?
You may try something like a cross join to find all combinations, then order by the difference. If your table name was foo something similar to:
SELECT set1.id, set2.id, abs(set1.the_geom - set2.the_geom) --- May want to use earth_distance extension ehre
FROM foo set1, foo set2
WHERE set1.id != set2.id
ORDER BY 3 DESC;
And if you need earth distance to calculate the distance itself - http://www.postgresql.org/docs/9.3/static/earthdistance.html

self join query issues with PostGIS

I have a table and I am doing a self join on it with geo-spacial functions fro PostgreSQL. Now I am expecting to build the point of intersections of each intersection except for those that has the attribute 'tunnel_road' having same values.
Therefore I have two rows conatining the value 'tunnel' which I don't want to build a point of intersection between them.
The query I am using is the following, though it is not working properly since it still is creating a point of intersection between the two lines.
insert into temp_intersect
select nextval('road_intersection_id_seq'), a.road_id, b.road_id, st_intersection(a.road, b.road), st_centroid(st_intersection(a.road, b.road))
from polygon_road a, polygon_road b
where st_intersects(a.road, b.road) AND a.road_id < b.road_id AND a.tunnel_road != b.tunnel_road
Any suggestions please?
the following is the table from which I am getting my data. As one can notice there is two rows containing the same value for the tunnel_road column where there is the id = 47 and 73

Select pair of rows that obey a rule

I have a big table (1M rows) with the following columns:
source, dest, distance.
Each row defines a link (from A to B).
I need to find the distances between a pair using anoter node.
An example:
If want to find the distance between A and B,
If I find a node x and have:
x -> A
x -> B
I can add these distances and have the distance beetween A and B.
My question:
How can I find all the nodes (such as x) and get their distances to (A and B)?
My purpose is to select the min value of distance.
P.s: A and B are just one connection (I need to do it for 100K connections).
Thanks !
As Andomar said, you'll need the Dijkstra's algorithm, here's a link to that algorithm in T-SQL: T-SQL Dijkstra's Algorithm
Assuming you want to get the path from A-B with many intermediate steps it is impossible to do it in plain SQL for an indefinite number of steps. Simply put, it lacks the expressive power, see http://en.wikipedia.org/wiki/Expressive_power#Expressive_power_in_database_theory . As Andomar said, load the data into a process and us Djikstra's algorithm.
This sounds like the traveling salesman problem.
From a SQL syntax standpoint: connect by prior would build the tree your after using the start with and limit the number of layers it can traverse; however, doing will not guarantee the minimum.
I may get downvoted for this, but I find this an interesting problem. I wish that this could be a more open discussion, as I think I could learn a lot from this.
It seems like it should be possible to achieve this by doing multiple select statements - something like SELECT id FROM mytable WHERE source="A" ORDER BY distance ASC LIMIT 1. Wrapping something like this in a while loop, and replacing "A" with an id variable, would do the trick, no?
For example (A is source, B is final destination):
DECLARE var_id as INT
WHILE var_id != 'B'
BEGIN
SELECT id INTO var_id FROM mytable WHERE source="A" ORDER BY distance ASC LIMIT 1
SELECT var_id
END
Wouldn't something like this work? (The code is sloppy, but the idea seems sound.) Comments are more than welcome.
Join the table to itself with destination joined to source. Add the distance from the two links. Insert that as a new link with left side source, right side destination and total distance if that isn't already in the table. If that is in the table but with a shorter total distance then update the existing row with the shorter distance.
Repeat this until you get no new links added to the table and no updates with a shorter distance. Your table now contains a link for every possible combination of source and destination with the minimum distance between them. It would be interesting to see how many repetitions this would take.
This will not track the intermediate path between source and destination but only provides the shortest distance.
IIUC this should do, but I'm not sure if this is really viable (performance-wise) due to the big amount of rows involved and to the CROSS JOIN
SELECT
t1.src AS A,
t1.dest AS x,
t2.dest AS B,
t1.distance + t2.distance AS total_distance
FROM
big_table AS t1
CROSS JOIN
big_table AS t2 ON t1.dst = t2.src
WHERE
A = 'insert source (A) here' AND
B = 'insert destination (B) here'
ORDER BY
total_distance ASC
LIMIT
1
The above snippet will work for the case in which you have two rows in the form A->x and x->B but not for other combinations (e.g. A->x and B->x). Extending it to cover all four combiantions should be trivial (e.g. create a view that duplicates each row and swaps src and dest).