SQL Academy · Les

Ruimtelijke joins en containment

Welke punten in welke gebieden vallen

Les 3 van 413 stappen

Ruimtelijke joins en containment is een gratis SQL Academy-les op CoddyKit. Dit is les 3 van 4. Je kunt de volledige les hieronder gratis lezen en daarna in de browser praktisch oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject SQL Academy. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus SQL Academy bevat in totaal 4 lessen.

Wat is een ruimtelijke join?

Een ruimtelijke join combineert twee tabellen op basis van een geografische relatie in plaats van een overeenkomende sleutel. In plaats van te vragen "is deze ID gelijk aan die ID?", stel je vragen zoals "valt dit punt binnen die polygoon?" of "overlappen deze twee vormen?"

PostGIS breidt PostgreSQL uit met geometrie typen en ruimtelijke functies die deze joins mogelijk maken. Het resultaat is hetzelfde als bij een gewone SQL JOIN — rijen uit beide tabellen worden gecombineerd — maar de voorwaarde is geometrisch.

Voorbeeldtabellen instellen

Laten we twee tabellen maken om mee te werken: cities, waarin puntlocaties worden opgeslagen, en countries, waarin polygoongrenzen worden opgeslagen. Beide gebruiken het type GEOMETRY van PostGIS met SRID 4326 (de standaard voor WGS84-breedte- en lengtegraad).

De SRID (ruimtelijke referentie-id) geeft aan welk coördinatensysteem PostGIS moet gebruiken. SRID 4326 is het meest gebruikelijk voor GPS-gegevens.

CREATE TABLE countries (
  id     SERIAL PRIMARY KEY,
  name   TEXT NOT NULL,
  border GEOMETRY(POLYGON, 4326)
);

CREATE TABLE cities (
  id       SERIAL PRIMARY KEY,
  name     TEXT NOT NULL,
  location GEOMETRY(POINT, 4326)
);

Voorbeeldgegevens invoegen

We gebruiken ST_GeomFromText om geometriewaarden in te voegen vanuit de indeling Well-Known Text (WKT). WKT is een standaardtekstweergave voor geometrieën: POINT(lon lat) voor punten en POLYGON((...)) voor polygonen.

Let erop dat de lengtegraad in WKT vóór de breedtegraad komt — dit komt overeen met de X-, Y-conventie in de wiskunde.

INSERT INTO countries (name, border) VALUES
  ('France', ST_GeomFromText('POLYGON((-5 42, 8 42, 8 51, -5 51, -5 42))', 4326)),
  ('Spain',  ST_GeomFromText('POLYGON((-9 36, 3 36, 3 44, -9 44, -9 36))', 4326));

INSERT INTO cities (name, location) VALUES
  ('Paris',    ST_GeomFromText('POINT(2.35 48.85)',   4326)),
  ('Madrid',   ST_GeomFromText('POINT(-3.70 40.42)',  4326)),
  ('Bordeaux', ST_GeomFromText('POINT(-0.58 44.84)',  4326)),
  ('Lisbon',   ST_GeomFromText('POINT(-9.14 38.72)',  4326));

ST_Contains: de kernfunctie

ST_Contains(geometry A, geometry B) geeft TRUE terug wanneer geometrie A geometrie B volledig bevat. In ons geval geeft ST_Contains(country.border, city.location) waar terug wanneer een stads punt binnen een landspolygoon ligt.

Dit vormt de kern van joins voor insluiting in PostGIS. De functie maakt deel uit van de OGC-standaard en werkt voor elke combinatie van geometriesoorten.

SELECT
  ci.name  AS city,
  co.name  AS country
FROM   cities   ci
JOIN   countries co
  ON   ST_Contains(co.border, ci.location);

ST_Within: het omgekeerde perspectief

ST_Within(geometry A, geometry B) is precies het tegenovergestelde van ST_Contains: de functie geeft TRUE terug wanneer geometrie A volledig binnen geometrie B ligt. ST_Within(city, country) is logisch identiek aan ST_Contains(country, city).

Beide functies leveren hier hetzelfde resultaat op. De keuze tussen beide is een kwestie van leesbaarheid — kies de functie die voor je query het natuurlijkst leest.

-- These two queries return identical results:

-- Using ST_Contains (country contains city)
SELECT ci.name, co.name
FROM   cities ci
JOIN   countries co ON ST_Contains(co.border, ci.location);

-- Using ST_Within (city is within country)
SELECT ci.name, co.name
FROM   cities ci
JOIN   countries co ON ST_Within(ci.location, co.border);

LEFT JOIN gebruiken om niet-gematchte punten te vinden

Een gewone JOIN laat steden weg die niet binnen een landspolygoon vallen. Gebruik een LEFT JOIN in combinatie met een controle op WHERE ... IS NULL om punten te vinden die geen omhullende polygoon hebben — handig om problemen met de gegevenskwaliteit of punten buiten je dekkingsgebied op te sporen.

SELECT
  ci.name  AS city,
  co.name  AS country
FROM   cities   ci
LEFT JOIN countries co
  ON   ST_Contains(co.border, ci.location)
ORDER BY co.name NULLS LAST;

Punten per polygoon tellen

Ruimtelijke joins komen goed tot hun recht in combinatie met aggregatie. Door steden aan landen te koppelen en vervolgens per land te groeperen, kun je tellen hoeveel punten binnen elke polygoon vallen. Dit patroon komt zeer vaak voor in geografische analyses — winkels per regio, evenementen per district, sensoren per zone enzovoort tellen.

SELECT
  co.name          AS country,
  COUNT(ci.id)     AS city_count
FROM   countries co
LEFT JOIN cities  ci
  ON   ST_Contains(co.border, ci.location)
GROUP BY co.name
ORDER BY city_count DESC;

Een ruimtelijke index gebruiken voor betere prestaties

Ruimtelijke joins kunnen traag zijn bij grote gegevensverzamelingen, omdat elk punt tegen elke polygoon wordt gecontroleerd. Met een GIST-index (Generalized Search Tree) kan PostGIS een voorfilter met begrenzende rechthoeken gebruiken, zodat de meeste vergelijkingen worden overgeslagen voordat de nauwkeurige ST_Contains-controle wordt uitgevoerd.

Maak altijd een GIST-index op geometriekolommen waarop je koppelt of filtert. De queryplanner gebruikt deze automatisch.

-- Create GIST indexes on both geometry columns
CREATE INDEX idx_countries_border
  ON countries USING GIST (border);

CREATE INDEX idx_cities_location
  ON cities USING GIST (location);

-- The same join now benefits from index acceleration
SELECT ci.name, co.name
FROM   cities ci
JOIN   countries co
  ON   ST_Contains(co.border, ci.location);

ST_Intersects: overlappende geometrieën

ST_Intersects(A, B) geeft TRUE terug als twee geometrieën ook maar één gemeenschappelijk punt hebben — zelfs als ze elkaar alleen aan een grens raken. De functie is minder strikt dan ST_Contains: twee overlappende polygonen snijden elkaar, ook als geen van beide de andere volledig bevat.

Voor controles of een punt binnen een polygoon ligt zijn ST_Intersects en ST_Contains gelijkwaardig, maar ST_Intersects gebruikt de GIST-index efficiënter en heeft in de praktijk vaak de voorkeur.

-- ST_Intersects is index-friendly and equivalent
-- to ST_Contains for point-in-polygon tests
SELECT
  ci.name  AS city,
  co.name  AS country
FROM   cities   ci
JOIN   countries co
  ON   ST_Intersects(co.border, ci.location);

Punten koppelen aan de dichtstbijzijnde polygoon

Wanneer een punt precies op een grens ligt of zeer dicht bij meerdere polygonen ligt, wil je misschien de dichtstbijzijnde polygoon vinden in plaats van alle overeenkomsten. ST_Distance meet de afstand tussen twee geometrieën, waardoor patronen met ORDER BY + LIMIT mogelijk worden, of de gespecialiseerde LATERAL-join met ORDER BY ... LIMIT 1.

Dit heet een join op de dichtstbijzijnde buur en komt vaak voor bij het koppelen van GPS-tracés aan wegsegmenten of het toewijzen van een punt aan de dichtstbijzijnde regio.

-- For each city, find the single closest country centroid
SELECT DISTINCT ON (ci.name)
  ci.name                              AS city,
  co.name                              AS nearest_country,
  ST_Distance(ci.location, ST_Centroid(co.border)) AS dist
FROM   cities   ci
CROSS JOIN countries co
ORDER BY ci.name, dist;

Praktijkvoorbeeld: restaurants in districten

Hier is een realistisch voorbeeld van begin tot eind: bepalen in welk stadsdistrict elk restaurant ligt en vervolgens restaurants per district tellen. Dit patroon is van toepassing op elk scenario met punten in polygonen — geldautomaten in wijken, ongevallen in politiedistricten, bestellingen in bezorgzones.

De query gebruikt ST_Within binnen een ruimtelijke join en groepeert de resultaten voor een samenvattend rapport.

-- Assume tables: districts(id, name, boundary GEOMETRY)
--                restaurants(id, name, location GEOMETRY)

SELECT
  d.name                 AS district,
  COUNT(r.id)            AS restaurant_count,
  STRING_AGG(r.name, ', ' ORDER BY r.name) AS names
FROM   districts    d
LEFT JOIN restaurants r
  ON   ST_Within(r.location, d.boundary)
GROUP BY d.name
ORDER BY restaurant_count DESC;

Korte controle

Controleer je begrip van ruimtelijke joins en insluiting in PostGIS.

Samenvatting: ruimtelijke joins en insluiting

In deze les heb je geleerd hoe je met ruimtelijke joins van PostGIS de vraag "welke punten liggen in welke gebieden?" beantwoordt.

Belangrijkste punten:

  • ST_Contains(polygon, point) — geeft waar terug wanneer de polygoon het punt volledig bevat.
  • ST_Within(point, polygon) — het omgekeerde; logisch gelijk aan ST_Contains.
  • ST_Intersects — een algemenere controle op overlap; efficiënt voor de index bij controles van punten in polygonen.
  • GIST-indexen op geometriekolommen zijn essentieel voor goede prestaties op grote schaal.
  • Combineer ruimtelijke joins met GROUP BY om punten per regio te tellen of te aggregeren.
  • Gebruik LEFT JOIN om punten te vinden die buiten alle polygonen vallen.

Ruimtelijke joins maken geografische analyse rechtstreeks in SQL mogelijk — zonder extern GIS-hulpmiddel.

Gratis beginnen

Leer SQL met een AI-tutor — gratis

Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.

Cursussen
46
Lessen
183

Veelgestelde vragen

Is de les “Ruimtelijke joins en containment” gratis?

Ja — de volledige tekst van “Ruimtelijke joins en containment” kun je hier gratis op het web lezen. Als je interactief wilt oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is, en de rest van de cursus SQL Academy wilt ontgrendelen, kun je upgraden naar CoddyKit PRO. De cursus SQL Academy bevat in totaal 4 lessen.

Wat leer ik in “Ruimtelijke joins en containment”?

Welke punten in welke gebieden vallen Je oefent met SQL Academy door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.

Heb ik ervaring nodig om met SQL Academy te beginnen?

Ervaring vooraf is niet nodig. SQL Academy op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 3 van 4.

Hoe lang duurt de les “Ruimtelijke joins en containment”?

De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.

Kan ik code schrijven en uitvoeren in deze les over SQL Academy?

Ja. Elke les over SQL Academy bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.

Alle lessen in deze cursus

  1. Ruimtelijke gegevenstypen
  2. Afstand en nearest neighbors
  3. Ruimtelijke joins en containment
  4. Ruimtelijke indexen (GiST)
← Terug naar SQL Academy