Search code examples
geometrypostgisspatial-querysubquery

How to include three geometries in one query - PostGIS


I am new to SQL and I am having difficulty creating a query which includes three geometries. I have a point layer (building) from which I want to count all the points-buildings that they have a maximum distance of 50 meters from the lines (roads) in a certain polygon (municipal unit) using some extra criteria for the two out of three tables.

Here's the table structure:

Table 1: building (id_building, address_name,color_tagged,point)
Table 2: roads (id_road, line) 
Table 3: munic_units (id_munic, munic_name, polygon)

I tried the code below and I have made a lot of changes..but it gives me errors. I would be glad to hear any suggestions. Thank you.

SELECT address_name, count(*) AS Frequency,munic_name,color_tagged
FROM building,roads,munic_units 
WHERE ST_CONTAINS((SELECT polygon FROM munic_units WHERE munic_name=''),(ST_DWithin((SELECT point FROM building WHERE color_tagged=''),line,50))) 
GROUP BY address_name,munic_name,color_tagged 
ORDER BY Frequency DESC,address_name DESC;

First, I tried a simpler version with two geometries:

SELECT address_name, count(*) AS Frequency,color_tagged
FROM building,roads,loc_munic_units
WHERE ST_Dwithin(point,roads_geom,50) AND color_tagged='YELLOW'
GROUP BY address_name,color_tagged
ORDER BY Frequency DESC,address_name DESC;

and returns...enter image description here ..the expected result in this stage was to find all the buildings in a distance of 50 meters from roads which have color_tagged as 'Yellow'. The final desired result is to run the previous search only in a specific area - one polygon.The structure of tables is as showed below.


Solution

  • You are close to the solution. The 1st query fails because you are not properly joining the tables. The 2nd query likely returns over-estimated counts because you do a cross join with the city table.

    Using the 2nd query, you can add the missing join condition (and properly write the joins)

    SELECT address_name, count(*) AS Frequency,color_tagged
    FROM building b  --selects from buildings
     JOIN roads r ON ST_Dwithin(b.point,r.roads_geom,50) -- when building is within 50 of a road
     JOIN loc_munic_units m ON ST_WITHIN(r.roads_geom, m.polygon) -- and when the road is within a municipality polygon
    WHERE b.color_tagged='YELLOW' AND m.munic_name = 'abc' -- restrain to a specific municipality (or >1) and color
    GROUP BY address_name,color_tagged
    ORDER BY Frequency DESC,address_name DESC;