Search code examples
sqlpostgresqlpostgis

How to create pairs of polygons Only in a specific (bigger) polygon and count all that points that are included in that pairs?


I am trying to create pairs of polygons in a bigger polygon (a chosen island) and also I would like to count all the points that are included in each one of the smaller polygons. At first, I was trying the above and I get all the pairs, also from other islands. The tables that I am using are

Table 1: polygon (polygon_id,polyg_geom, name)
Table 2: polyg_island (polyg_island_id,polyg_island_geom,name_island)
Table 3: pos (pos_id,point,address)

SELECT P1.name, P2.name
FROM polygon P1, polygon P2
WHERE ST_TOUCHES(P1.polyg_geom, P2.polyg_geom)
AND P1.polyg_id < P2.polyg_id;

When I was trying to join the table of island polygon, in order to reduce the result to one island, the query returns empty.Getting that error, it was difficult to add the part of counting the points in each pair.

SELECT P1.name, P2.name
FROM polygon P1, polygon P2
JOIN polygon_island ON ST_Overlaps(polyg_geom,polyg_island_geom)
AND polygon_island.name_island='...'
WHERE ST_TOUCHES(P1.polyg_geom, P2.polyg_geom)
AND P1.polyg_id < P2.polyg_id
;
Is there any suggestion on what I am doing wrong at this stage. Thank you!

Edited answer: The query that I have written below without (with) is running, except from when I am inserting that part.It returns empty.

WHERE ST_Overlaps(P1.polyg_geom,(select island_geom from polyg_island WHERE name='...'))AND
      ST_Overlaps(P2.polyg_geom,(select island_geom from polyg_island WHERE name='..'))AND

SELECT P1.name AS P1_name, 
  (SELECT count(id_pos) FROM pos WHERE ST_Contains(P1.polyg_geom,point))AS count1,
  P2.name as P2_name,
  (SELECT count(id_pos) FROM pos WHERE ST_Contains(P2.polyg_geom,point)) AS count2
FROM polygon P1, polygon P2,pos,polyg_island
WHERE ST_Overlaps(P1.polyg_geom,(select island_geom from polyg_island WHERE name='...')) AND
      ST_Overlaps(P2.polyg_geom,(select island_geom from polyg_island WHERE name='..')) AND
      ST_TOUCHES(P1.polyg_geom, P2.polyg_geom) AND
      P1.polyg_id < P2.polyg_id;


Solution

  • Without any data or sample of an expected result it is quite hard to figure out what exactly your use case is. But I believe you're just missing a single step. Maybe this CTE will help you:

    WITH j AS (
      SELECT P1.polyg_geom AS poly_p1,
             P2.polyg_geom AS poly_p2
      FROM polygon P1, polygon P2
      WHERE ST_TOUCHES(P1.polyg_geom, P2.polyg_geom)
        AND P1.polygon_id < P2.polygon_id)
    SELECT *, 
       (SELECT count(*) FROM pos
        WHERE ST_Contains(poly_p3.polyg_island_geom,point))
    FROM polyg_island poly_p3,j
    WHERE ST_Contains(j.poly_p1,polyg_island_geom) AND
          ST_Contains(j.poly_p2,polyg_island_geom);
    

    Or maybe this

    WITH j AS (
      SELECT P1.polyg_geom AS poly_p1,
             P2.polyg_geom AS poly_p2,
             P1.name AS p1_name, P2.name AS p2_name
      FROM polygon P1, polygon P2
      WHERE ST_TOUCHES(P1.polyg_geom, P2.polyg_geom)
        AND P1.polygon_id < P2.polygon_id)
    SELECT 
      j.p1_name, (SELECT count(*) FROM pos WHERE ST_Contains(j.poly_p1,point)),
      j.p2_name, (SELECT count(*) FROM pos WHERE ST_Contains(j.poly_p2,point))
    FROM j