nav_exclude |
---|
true |
{: .no_toc }
- TOC {:toc}
A simple query to do this is:
SELECT pt.id, poly.*
FROM grid pt
JOIN polygons poly ON ST_Intersects(poly.geom, pt.geom);
Caveat: this will return multiple records if a point lies in multiple polygons. To ensure only a single record is returned per point, and also to include points which do not lie in any polygon, use:
SELECT pt.id, poly.*
FROM grid pt
LEFT OUTER JOIN LATERAL
(SELECT * FROM polygons poly
WHERE ST_Intersects(poly.geom, pt.geom) LIMIT 1) AS poly ON true;
SELECT
polyname,
count(pid) FILTER (WHERE pid='w') AS "w",
count(pid) FILTER (WHERE pid='x') AS "x",
count(pid) FILTER (WHERE pid='y') AS "y",
count(pid) FILTER (WHERE pid='z') AS "z"
FROM polygons
LEFT JOIN points ON st_intersects(points.geom, polygons.geom)
GROUP BY polyname;
Count lightning occurences inside countries
Count occurences inside river polygons
https://gis.stackexchange.com/questions/185381/optimising-a-very-large-point-in-polygon-query
https://gis.stackexchange.com/questions/220313/point-within-a-polygon-within-another-polygon
Choose containing polygon with smallest area
SELECT DISTINCT ON (compequip.id), compequip.*, a.*
FROM compequip
LEFT JOIN a
ON ST_within(compequip.geom, a.geom)
ORDER BY compequip.id, ST_Area(a.geom)
https://gis.stackexchange.com/questions/139880/postgis-st-within-or-st-disjoint-performance-issues
This is not PiP, but the solution of using NOT EXISTS might be applicable?
Given 2 tables:
obstacles
- Point layer with a columnheight_m INTEGER
polyobstacles
- Polygon layer
Select the highest obstacle in each polygon. If there are several points with the same highest height a random one of those is selected.
SELECT poly.id, obs_max.*
FROM polyobstacle poly
JOIN LATERAL (SELECT * FROM obstacles o
WHERE ST_Contains(poly.geom, o.geom)
ORDER BY height_m LIMIT 1
) AS obs_max ON true;
Do a spatial join between polygon and points and use SELECT DISTINCT ON (poly.id) poly.id, o.height...
SELECT p.id, (array_agg(o.id order by height_m))[1] AS highest_id
FROM polyobstacles p JOIN obstacles o ON ST_Contains(p.geom, o.geom)
GROUP BY p.id;
Basic query - with tables of address points and US census blocks, find state for each point Discusses required indexes, and external parallelization https://lists.osgeo.org/pipermail/postgis-users/2020-May/044161.html
SELECT ply.polyname, SUM(pnt1.cnt) AS pointtable1count, SUM(pnt2.cnt) AS pointtable2count
FROM polytable AS ply,
LATERAL (
SELECT COUNT(pt.*) AS cnt
FROM pointtable1 AS pt
WHERE ST_Intersects(ply.geom, pt.geom)
) AS pnt1,
LATERAL (
SELECT COUNT(c.*) AS cnt
FROM pointtable2 AS pt
WHERE ST_Intersects(ply.geom, pt.geom)
) AS pnt2
GROUP BY 1;
https://gis.stackexchange.com/questions/134244/query-road-shape?noredirect=1&lq=1
https://gis.stackexchange.com/questions/20835/identifying-road-intersections-using-postgis
https://gis.stackexchange.com/questions/349994/st-intersects-with-multiple-geometries
Nice application of counting using HAVING
clause.
SELECT lines.id, lines.geom
FROM lines
JOIN polygons ON st_intersects(lines.geom,polygons.geom)
WHERE polygons.id in (1,2)
GROUP BY lines.id, lines.geom
HAVING count(*) = 2;
https://gis.stackexchange.com/questions/374459/postgis-validate-the-z-continuity
Assuming the LineStrings are digitized in the correct order (start point is most elevated), this returns all vertices geom, their respective line , and their position in the vertices array of that line, for all vertices with higher Z value as their predecessor.
SELECT ln_id, vtx_id, geom
FROM (SELECT ln.<id> AS ln_id,
dmp.path[1] AS vtx_id,
dmp.geom,
ST_Z(dmp.geom) < LAG(ST_Z(dmp.geom)) OVER(PARTITION BY ln.<id> ORDER BY dmp.path[1]) AS is_valid
FROM <lines> AS ln,
LATERAL ST_DumpPoints(ln.geom) AS dmp
) q
WHERE NOT is_valid;
https://gis.stackexchange.com/questions/224138/postgis-st-intersects-vs-arcgis-select-by-location
Use NOT EXISTS:
SELECT * FROM polygons
WHERE NOT EXISTS (SELECT 1 FROM streets WHERE ST_Intersects(polygons.geom, streets.geom))
Use the LEFT JOIN on ST_Contains
with NULL result pattern
https://gis.stackexchange.com/questions/212543/compare-row-to-all-others-in-postgis
For each polygon, compute union of polygons which intersect it, then test if the union covers the polygon
WITH
data(id, geom) AS (VALUES
( 1, 'POLYGON ((100 200, 200 200, 200 100, 100 100, 100 200))'::geometry ),
( 2, 'POLYGON ((250 150, 200 150, 200 250, 250 250, 250 150))'::geometry ),
( 3, 'POLYGON ((300 100, 250 100, 250 150, 300 150, 300 100))'::geometry )
)
SELECT a.id, b.id,
ST_Relate(a.geom, b.geom),
ST_Relate(a.geom, b.geom, '****1****') AS is_line_touch
FROM data a CROSS JOIN data b WHERE a.id < b.id;
Find polygons where total length of intersection with others is less than length of boundary
SELECT a.id
FROM data a
INNER JOIN data b ON (ST_Intersects(a.geom, b.geom) AND a.id != b.id)
GROUP BY a.id
HAVING 1e-6 >
abs(ST_Length(ST_ExteriorRing(a.geom)) -
sum(ST_Length(ST_Intersection(ST_Exteriorring(a.geom), ST_ExteriorRing(b.geom)))));
https://gis.stackexchange.com/questions/11510/st-closestpointline-point-does-not-intersect-line
Also https://gis.stackexchange.com/questions/350461/find-path-containing-point
https://gis.stackexchange.com/questions/131806/find-start-of-river https://gis.stackexchange.com/questions/132266/find-headwater-polygons?noredirect=1&lq=1
https://gis.stackexchange.com/questions/160142/intersection-between-line-polygon-in-postgis
SELECT lines.geom
FROM lines, polygons
WHERE ST_Touches(lines.geom, polygons.geom) AND
NOT EXISTS (SELECT 1 FROM polygons p2 WHERE ST_Crosses(lines.geom, p2.geom));
A table of polygons which form a set of nested hierarchical coverages, but coverage hierarchy is not explicitly represented.
Determine contains relationships based on interior points and areas. Can use a recursive query on that to extract paths if needed.
WITH RECURSIVE data(id, geom) AS (VALUES
('AC11', 'POLYGON ((100 200, 150 200, 150 150, 100 150, 100 200))'),
('AC12', 'POLYGON ((200 200, 200 150, 150 150, 150 200, 200 200))'),
('AC21', 'POLYGON ((200 100, 150 100, 150 150, 200 150, 200 100))'),
('AC22', 'POLYGON ((100 100, 100 150, 150 150, 150 100, 100 100))'),
('AC1', 'POLYGON ((200 200, 200 150, 100 150, 100 200, 200 200))'),
('AC2', 'POLYGON ((200 100, 100 100, 100 150, 200 150, 200 100))'),
('AC', 'POLYGON ((100 200, 200 200, 200 100, 100 100, 100 200))'),
('AB1', 'POLYGON ((100 300, 150 300, 150 200, 100 200, 100 300))'),
('AB2', 'POLYGON ((200 300, 200 200, 150 200, 150 300, 200 300))'),
('AB', 'POLYGON ((100 300, 200 300, 200 200, 100 200, 100 300))'),
('AA', 'POLYGON ((0 300, 100 300, 100 100, 0 100, 0 300))'),
('A', 'POLYGON ((200 100, 0 100, 0 300, 200 300, 200 100))')
),
-- compute all containment links
contains AS ( SELECT p.id idpar, c.id idch, ST_Area(p.geom) par_area
FROM data p
JOIN data c ON ST_Contains(p.geom, ST_PointOnSurface(c.geom))
WHERE ST_Area(p.geom) > ST_Area(c.geom)
),
-- extract direct containment links, by choosing parent with min area
pcrel AS ( SELECT DISTINCT ON (idch) idpar, idch
FROM contains ORDER BY idch, par_area ASC
),
-- compute paths as strings
pcpath(id, path) AS (
SELECT 'A' AS id, 'A' AS path
UNION ALL
SELECT idch AS id, path || ',' || idch
FROM pcpath JOIN pcrel ON pcpath.id = pcrel.idpar
)
SELECT * FROM pcpath;
https://gis.stackexchange.com/questions/268147/find-linestrings-with-common-segments-in-postgis-2-3
SELECT ST_Relate('LINESTRING(0 0, 2 0)'::geometry,
'LINESTRING(1 0, 2 0)'::geometry,
'1********');
Good use case for JOIN LATERAL
SELECT bg.geoid, bg.geom, bg.total_pop AS total_population,
bg.med_inc AS median_income,
t.numbirds
FROM bg_pop_income bg
JOIN LATERAL
(SELECT COUNT(1) as numbirds
FROM bird_loc bl
WHERE ST_within(bl.loc, bg.geom)) AS t ON true;
Almost certainly less performant
SELECT bg.geoid, bg.geom, bg.total_pop, bg.med_inc,
COUNT(bl.global_unique_identifier) AS num_bird_counts
FROM bg_pop_income bg
LEFT OUTER JOIN bird_loc bl ON ST_Contains(bg.geom, bl.loc)
GROUP BY bg.geoid, bg.geom, bg.total_pop, bg.med_inc;
(Question is for ArcGIS; would be interesting to provide a PostGIS answer)
https://gis.stackexchange.com/questions/389448/postgis-count-adjacent-polygons-connected-by-line (First query)
SELECT a.id, a.geom, a.codistat, a.name, num_adj
FROM municipal a
JOIN LATERAL (SELECT COUNT(1) num_adj
FROM municipal b
WHERE ST_Intersects(a.geom, b.geom)
) t ON true;
https://gis.stackexchange.com/questions/389448/postgis-count-adjacent-polygons-connected-by-line
SELECT a.id, a.geom, a.codistat, a.name, num_adj
FROM municipal a
JOIN LATERAL (SELECT COUNT(1) num_adj
FROM municipal b
JOIN way w
ON ST_Intersects(b.geom, w.geom)
WHERE ST_Intersects(a.geom, b.geom)
AND ST_Intersects(a.geom, w.geom)
) t ON true;
https://gis.stackexchange.com/questions/349251/finding-median-of-polygons-that-share-boundaries
SELECT county, SUM(ST_Length(ST_Intersection(counties.geom,routes.geom)))
FROM counties
JOIN routes ON ST_Intersects(counties.geom, routes.geom)
GROUP BY county;
See following (but answers are not great) https://gis.stackexchange.com/questions/143438/calculating-total-line-lengths-within-polygon
https://gis.stackexchange.com/questions/172266/improve-performance-of-a-postgis-st-dwithin-query
https://gis.stackexchange.com/questions/209959/how-to-use-st-intersects-with-different-geometry-type
This may be due to indexing being used for first ST_Intersects arg, but not second?
https://gis.stackexchange.com/questions/240721/postgis-performance-increase-with-cluster
https://gis.stackexchange.com/questions/237709/speeding-up-intersect-query-in-postgis
https://gis.stackexchange.com/questions/356497/select-points-falling-outside-of-buffer-and-count https://gis.stackexchange.com/questions/367594/get-all-geom-points-that-are-more-than-3-meters-from-the-linestring-at-big-scal
SELECT locations.geom FROM locations
EXCEPT
SELECT locations.geom FROM ways
JOIN locations
ON ST_DWithin( ways.linestring, locations.geom, 3)
2x SLOWER than #1
SELECT inj.*
FROM injuries inj
LEFT JOIN bike_routes br
ON ST_DWithin(inj.geom, br.geom, 15)
WHERE br.gid IS NULL
Same performance as #2 ?
SELECT *
FROM injuries AS inj
WHERE NOT EXISTS
(SELECT 1 FROM bike_routes br
WHERE ST_DWithin(br.geom, inj.geom, 15);
Buffer line, union, then find all point not in buffer polygon
https://gis.stackexchange.com/questions/356663/postgis-finding-duplicate-label-within-a-radius
(Note: question title is misleading, question is actually asking for points which do NOT have a nearby point) Solution Best way is to use NOT EXISTS. To select only records that have no other point with the same value within distance:
SELECT *
FROM points AS a
WHERE NOT EXISTS (
SELECT 1
FROM points
WHERE a.cat = cat AND a.id <> id AND ST_DWithin(a.geom, geom, <threshold_in_CRS_units>)
);
https://stackoverflow.com/questions/31497071/farthest-distance-of-a-polygon-point-from-its-centroid
https://gis.stackexchange.com/questions/24818/remove-duplicate-points-based-on-a-specified-distance
https://gis.stackexchange.com/questions/17857/finding-points-within-elliptical-area-using-postgis
https://gis.stackexchange.com/questions/223154/find-highest-elevation-along-path
https://gis.stackexchange.com/questions/287774/nearest-neighbor
https://gis.stackexchange.com/questions/297208/efficient-way-to-find-nearest-feature-between-huge-postgres-tables Very thorough explanation, including difference between geom and geog
SELECT g1.gid AS gref_gid,
g2.gid AS gnn_gid,
g2.code_mun,
g1.codigo_mun,
g2.text,
g2.via AS igcvia1
FROM u_nomen_dom As g1
JOIN LATERAL (
SELECT gid,
code_mun,
text,
via
FROM u_nomen_via AS g
WHERE g1.codigo_mun = g.codigo_mun
ORDER BY g1.geom <-> g.geom
LIMIT 1
) AS g2
ON true;
https://gis.stackexchange.com/questions/136403/postgis-nearest-points-with-st-distance-knn Lots of obsolete options, dbastons answer is best
https://gis.stackexchange.com/questions/279387/automatically-snapping-points-to-closest-part-of-line
https://gis.stackexchange.com/questions/332019/distinct-st-shortestline
https://gis.stackexchange.com/questions/283794/get-barrier-edge-id
https://gis.stackexchange.com/questions/278357/how-to-update-with-lateral-nearest-neighbour-query https://gis.stackexchange.com/questions/338312/find-closest-polygon-from-point-and-get-its-attributes
https://carto.com/blog/lateral-joins/
Uses LATERAL and KNN <->
SELECT a.id,
a.geom,
avg(c.temp_val) temp_val
FROM tablea a
CROSS JOIN LATERAL
(SELECT temp_val
FROM tableb b
ORDER BY b.geom <-> a.geom
LIMIT 4) AS c
GROUP BY a.id,a.geom
https://gis.stackexchange.com/questions/357237/find-knn-having-reference-in-a-table
UPDATE points
SET geom = (
SELECT ST_ClosestPoint(lines.geom, points.geom)
FROM lines
WHERE ST_DWithin(points.geom, lines.geom, 5)
ORDER BY lines.geom <-> points.geom
LIMIT 1
);
https://gis.stackexchange.com/questions/377674/find-nearest-polygons-of-a-multi-line-string
https://gis.stackexchange.com/questions/316128/identifying-long-and-narrow-polygons-in-with-postgis
Use function ST_MaximumInscribedCircle
to compute the radius of the Maximum Inscribed Circle of each polygon, and then select using desired cut-off.
This is much faster than computing negative buffers.
Detect thin polygons using a test: ST_Area(ST_Buffer(geom, -10)) = 0
.
This is not very performant.
Use the Thinness Ratio: TR(Area,Perimeter) = Area * 4 * pi / (Perimter^2)
.
This is only a heuristic approximation, and it's hard to choose appropriate cut-off for the value of the ratio.
See https://gis.stackexchange.com/questions/151939/explanation-of-the-thinness-ratio-formula
https://gis.stackexchange.com/questions/238748/compare-only-valid-polygon-geometries-in-postgis
https://gis.stackexchange.com/questions/124583/delete-duplicate-geometry-in-postgis-tables
Example: https://gis.stackexchange.com/questions/176359/tolerance-in-postgis
This post is about needing ST_Equals
to have a tolerance to accommodate small differences caused by reprojection
https://gis.stackexchange.com/questions/141790/postgis-st-equals-false-when-st-intersection-100-of-geometry
This is about small coordinate differences defeating ST_Equals
, and using ST_SnapToGrid
to resolve the problem:
https://gis.stackexchange.com/questions/56617/st-equals-postgis-problems
This says that copying geometries to another database causes them to fail ST_Equals
(not sure why copy would change the geom - perhaps done using WKT?). Says that using buffer is too slow
https://gis.stackexchange.com/questions/213240/st-equals-not-matching-with-exact-geometry
https://gis.stackexchange.com/questions/176359/tolerance-in-postgis
https://gis.stackexchange.com/questions/11510/st-closestpointline-point-does-not-intersect-line
Use ST_DWithin
Actually it doesn’t look like there is a discrepancy now. But still a case where a distance tolerance might clarify things.
https://gis.stackexchange.com/questions/136403/postgis-nearest-points-with-st-distance-knn
https://gis.stackexchange.com/questions/376706/postgis-st-covers-doesnt-match-polygon-after-st-union
WITH data(id, pt) AS (VAlUES
( 1, 'POINT ( 30.2833756 50.4419441) '::geometry )
,( 2, 'POINT( 30.2841370 50.4419441 ) '::geometry )
)
,poly AS (
SELECT ST_Transform(ST_Expand( ST_Transform(ST_SetSRID( pt, 4326) , 31997), 100), 3857) AS poly
FROM data
)
SELECT * FROM poly;
SELECT ST_Union( poly ) FROM poly;