Find islands using PostGIS
Assuming that you have a guaranteed topological equality between island and water polygon rings, using a simpler EXISTS
filter should increase performance:
SELECT a.id
FROM islands AS a
WHERE a.type <> 'water'
AND EXISTS (
SELECT 1
FROM islands AS b,
LATERAL ST_DumpRings(b.geom) AS dmp -- rings to polygons
WHERE b.type = 'water'
AND dmp.path[1] > 0 -- only interior rings
AND ST_Equals(a.geom, dmp.geom)
)
;
ST_DumpRings
is relatively cheap compared to constructing geometries, and enables finding matches more generically for all inner rings of a water body polygonEXISTS
will quit its execution once the first result row of its query is truthy- no additional aggregation (
GROUP BY
) required
@Cyril's answer will also work great with ST_DumpPoints
, i.e. using
...
tblb AS (SELECT dmp.geom FROM islands, LATERAL ST_DumpRings(geom) AS dmp WHERE type = 'water' AND dmp.path[1] > 0)
...
If topological equality is not guaranteed, you could check for ST_Within
on the exterior ring polygon:
SELECT a.id
FROM islands AS a
WHERE a.type <> 'water'
AND EXISTS (
SELECT 1
FROM islands AS b,
LATERAL ST_DumpRings(b.geom) AS dmp -- rings to polygon
WHERE b.type = 'water'
AND dmp.path[1] = 0 -- only exterior ring
AND ST_Within(a.geom, dmp.geom)
);
Here's another way to solve the question asked.
Run the script:
WITH
tbla AS (SELECT * FROM islands WHERE type = 'land'),
tblb AS (SELECT ST_InteriorRingN(geom,1) geom FROM islands WHERE type = 'water')
SELECT ID, type, (a.geom) geom FROM tbla a INNER JOIN tblb b ON ST_Intersects(a.geom, b.geom);
Check the result, and if I misunderstood the question, let me know.