How to Join Spatial Data with PostgreSQL/PostGIS | by Abdishakur | Towards Data Science

Joining data is a common task in the data science world. While the regular SQL table join is a great feature, I am most impressed by the real power of spatial joins.
With Spatial Join, you can correlate information from different tables based on their geometry relations. In this tutorial, we will see examples of spatial join and also summarizing features after the spatial join.
If you are new to the world of PostgreSQL/PostGIS, I have a beginner’s tutorial to set you up the environment and gets you started quickly with step by step guide.
towardsdatascience.com
We are using Barcelona Airbnb dataset for this tutorial with smaller statistical areas. Our task is to join the Airbnb public listings to the respective smaller statistical area they belong to. In other words, we would like to find out which area each Airbnb points falls in. Finally, we will summary the joined data to find out how many Airbnb guest houses each statistical area has.
Before we go through the spatial join, let us first familiarize our self with the dataset. We look at the public listings by querying these columns and limiting the result to the first 100 listings.
SELECT name, host_name, room_type, price, reviews_per_month, neighbourhood, geomFROM public.listingsLIMIT 100;
We display the result below of the first ten rows. We have the name of the listing, the hostname, room type, price, reviews, neighbourhoods and the geometry(Geom). The geometry column has a small eye that allows you to visualize the spatial data.
Here is the output of the geometry viewer for the Airbnb listings. Note that this is limited to the first 100 points only.
Now, let us look at the statistical area dataset. We simply limit the columns to the geometry and the code of the area.
SELECT aeb, geomFROM public.statistical_areas
The following map displays the Statistical area polygons visualized with PgAdmin4 Geometry Viewer.
Before, we move to carry out the spatial join, make sure to check out if the Coordinate Reference System (CRS) of both datasets match. We can simply query out the Spatial Reference System of each dataset like this.
SELECT ST_SRID(geom) FROM public.statistical_areasLIMIT 1;
And both datasets have WGS84 CRS, so we can go ahead and perform the spatial join.
We have seen the dataset and checked the CRS of the dataset. All is set now. To join both datasets, we can use different spatial relations including ST_Within ,ST_Contains, ST_Covers, orST_Crosses . In this example, we are using ST_Within to find out which point is within which polygon.
SELECT houses.name AS guest_name, houses.room_type as room,  houses.price as Price, areas.aeb AS statistical_codeFROM listings AS housesJOIN statistical_areas AS areasON ST_Within(houses.geom, areas.geom)
The result is this table with Airbnb listings with an additional column indicated which statistical area code each point belongs to as shown in below table.
Great! The spatial join could be your final results if you were after to find out only where each point belongs to. However, we might need to summarize the spatial join result to find out insights in the distribution of the dataset.
Any SQL aggregate function would work here to gain insights from the spatially joined dataset. Let us say we want to find out the average Airbnb listings prices for each statistical neighbourhoods.
We only need to use the Average aggregate function with listing prices and group the data by statistical area.
SELECT AVG(houses.price) AS AVG_Price, areas.aeb AS statistical_codeFROM listings AS housesJOIN statistical_areas AS areasON ST_Within(houses.geom, areas.geom)GROUP BY areas.aeb
The result is this table where we have the average price of each statistical area.
Here is a map showing the average price distribution for the statistical areas in Barcelona.
In this tutorial, we have seen how to do spatial join with PostGIS using real-world dataset. We successfully joined Airbnb listings to their respective statistical areas using geometry relations. You might experiment using ST_Contains to come up with the same results. You might also like to experiment with different aggregation functions, like counting the number of listings in each statistical area.