Skip to content

Instantly share code, notes, and snippets.

@bartzwemmer
Created July 15, 2026 08:02
Show Gist options
  • Select an option

  • Save bartzwemmer/bc91fde4976299ce1aaabfb14a7c5c7f to your computer and use it in GitHub Desktop.

Select an option

Save bartzwemmer/bc91fde4976299ce1aaabfb14a7c5c7f to your computer and use it in GitHub Desktop.
DuckDB SQL query to retrieve all current Panden (building foorprints) in The Netherlands from local BAG data.
-- Extensions, so we can read the zipped GML files
INSTALL spatial; LOAD spatial;
-- Combined Relational Model of BAG Objects (Panden, Verblijfsobjecten, Addresses, Public Spaces, Cities)
-- Filters active records (eindGeldigheid IS NULL AND tijdstipInactief IS NULL) to prevent historical duplicate versions.
WITH wpl_active AS (
SELECT
identificatie,
naam,
status,
geom
FROM ST_Read('/vsizip/panden/9999WPL08072026.zip')
WHERE eindGeldigheid IS NULL AND tijdstipInactief IS NULL
),
opr_active AS (
SELECT
identificatie,
naam,
type,
woonplaatsRef,
status,
geom
FROM ST_Read('/vsizip/panden/9999OPR08072026.zip')
WHERE eindGeldigheid IS NULL AND tijdstipInactief IS NULL
),
num_active AS (
SELECT
identificatie,
huisnummer,
huisletter,
huisnummerToevoeging,
postcode,
typeAdresseerbaarObject,
openbareruimteRef,
woonplaatsRef,
status,
geom
FROM ST_Read('/vsizip/panden/9999NUM08072026.zip')
WHERE eindGeldigheid IS NULL AND tijdstipInactief IS NULL
),
vbo_active AS (
SELECT
identificatie,
gebruiksdoel,
oppervlakte,
hoofdadresNummeraanduidingRef,
nevenadresNummeraanduidingRef,
pandRef,
status,
geom
FROM ST_Read('/vsizip/panden/9999VBO08072026.zip')
WHERE eindGeldigheid IS NULL AND tijdstipInactief IS NULL
),
pnd_active AS (
SELECT
identificatie,
oorspronkelijkBouwjaar,
status,
geom
FROM ST_Read('/vsizip/panden/9999PND08072026.zip')
WHERE eindGeldigheid IS NULL AND tijdstipInactief IS NULL
),
-- Flatten Verblijfsobjecten by unnesting the pandRef list to support optimized hash joining
vbo_flat AS (
SELECT
identificatie,
gebruiksdoel,
oppervlakte,
hoofdadresNummeraanduidingRef,
nevenadresNummeraanduidingRef,
unnest(pandRef) AS single_pand_ref,
status,
geom
FROM vbo_active
)
SELECT
-- Pand attributes
p.identificatie AS pand_identificatie,
p.oorspronkelijkBouwjaar AS pand_oorspronkelijkBouwjaar,
p.status AS pand_status,
p.geom AS pand_geom,
-- Verblijfsobject attributes
v.identificatie AS vbo_identificatie,
v.gebruiksdoel AS vbo_gebruiksdoel,
v.oppervlakte AS vbo_oppervlakte,
v.nevenadresNummeraanduidingRef AS vbo_nevenadres_refs,
v.status AS vbo_status,
v.geom AS vbo_geom,
-- Nummeraanduiding (Address) attributes
num.identificatie AS num_identificatie,
num.huisnummer AS num_huisnummer,
num.huisletter AS num_huisletter,
num.huisnummerToevoeging AS num_huisnummer_toevoeging,
num.postcode AS num_postcode,
num.typeAdresseerbaarObject AS num_type_adresseerbaar_object,
num.status AS num_status,
num.geom AS num_geom,
-- OpenbareRuimte (Public Space / Street) attributes
opr.identificatie AS opr_identificatie,
opr.naam AS opr_naam,
opr.type AS opr_type,
opr.status AS opr_status,
-- Woonplaats (City/Town) attributes
w.identificatie AS wpl_identificatie,
w.naam AS wpl_naam,
w.status AS wpl_status,
w.geom AS wpl_geom
FROM pnd_active p
-- LEFT JOIN ensures all panden are returned, even if they have no verblijfsobject, address, or town
LEFT JOIN vbo_flat v ON v.single_pand_ref = p.identificatie
LEFT JOIN num_active num ON v.hoofdadresNummeraanduidingRef = num.identificatie
LEFT JOIN opr_active opr ON num.openbareruimteRef = opr.identificatie
-- COALESCE resolves the Woonplaats: use the override on the Nummeraanduiding if present,
-- otherwise fall back to the Woonplaats of the OpenbareRuimte
LEFT JOIN wpl_active w ON COALESCE(num.woonplaatsRef, opr.woonplaatsRef) = w.identificatie
-- WHERE w.naam = 'Dordrecht'
-- AND unnest(v.gebruiksdoel) = 'Woonfunctie'
;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment