Lesson 6  ·  Oct 9, 2026
Data Engineering Fundamentals

Combining tables with JOIN

Real databases split data across tables: temperature_readings holds raw measurements keyed by station_id, while weather_stations holds the metadata — name, lat, lon. A JOIN stitches them back together on the shared key, one combined row per match.

The code

SELECT s.name, s.lat, s.lon, r.temp_c
FROM weather_stations AS s
JOIN temperature_readings AS r
  ON s.station_id = r.station_id
ORDER BY r.temp_c DESC
LIMIT 5;

Reading it piece by piece:

  1. AS s / AS r — short aliases so you write s.name instead of weather_stations.name.
  2. ON s.station_id = r.station_id — the match rule: a row pair survives only when the two IDs agree.
  3. Plain JOIN means INNER JOIN — only matches. A reading whose station_id is missing from the stations table silently drops out (which is also how joins audit broken keys).

In practice

Facts in one table, context in another — a data engineer joins them to build the dataset analysts actually query. Sensor readings + station metadata, orders + customers, events + users: same pattern everywhere. Most production queries you'll write are just JOIN + WHERE + GROUP BY composed together.

Python bridge: df_stations.merge(df_readings, on="station_id"). Pandas' .merge() is exactly an inner JOIN — SQL does it inside the warehouse so you never ship two big tables into Python.

Further reading

SQL INNER JOIN, animated with GIFs — Data School

Try it

Practice question: using these sample tables, write a query that lists name, lat, lon, and temp_c for all readings above 30°C, sorted by temperature descending.

weather_stations
station_idnamelatlon
1Princeton40.36-74.66
2Boulder40.02-105.27
3Houston29.76-95.37
temperature_readings
station_idtemp_crecorded_at
124.506:00
219.206:00
333.806:00
125.107:00
334.207:00
Show answer
SELECT s.name, s.lat, s.lon, r.temp_c
FROM weather_stations AS s
JOIN temperature_readings AS r
  ON s.station_id = r.station_id
WHERE r.temp_c > 30
ORDER BY r.temp_c DESC;
namelatlontemp_c
Houston29.76-95.3734.2
Houston29.76-95.3733.8

Only the two Houston readings clear 30°C — Princeton (25.1) and Boulder (19.2) don't. Note the duplicated Houston row: the join emits one output row per match, so a station with two readings appears twice. This is how one-to-many joins multiply rows, and why you can double-count if you aggregate after joining on a non-unique key.

← All posts