DataPartner365

Jouw partner voor datagedreven groei en inzichten

Data Modelleren Uitgelegd: Van Conceptueel Model tot Fysiek Databaseontwerp

Data modelleren is een van de meest fundamentele vaardigheden in de datawereld. Of je nu een database ontwerpt, een data warehouse bouwt of een Power BI-rapport maakt — zonder een goed datamodel werkt niets naar behoren. In dit artikel leggen we data modelleren van de grond af aan uit: van de theorie (conceptueel, logisch, fysiek model) tot ER-diagrammen, normalisatie en praktijkvoorbeelden met echte SQL-code.

Wat is Data Modelleren?

Data modelleren is het proces waarbij je de structuur van data vastlegt: welke gegevens worden opgeslagen, hoe ze met elkaar samenhangen en hoe ze georganiseerd worden in tabellen, kolommen en relaties. Een datamodel is als een plattegrond van je databasis: zonder goede plattegrond bouw je een chaotisch gebouw.

Een goed datamodel zorgt voor:

De Drie Niveaus van Data Modelleren

Data modelleren gebeurt op drie niveaus, elk met een ander detailniveau en een andere doelgroep:

1. Conceptueel Model

Het conceptuele model is het meest abstracte niveau. Het beschrijft wat er opgeslagen wordt, zonder technische details. Dit model wordt gemaakt samen met de business, niet door de IT-afdeling alleen. Het antwoordt op de vraag: welke concepten bestaan er in ons domein en hoe hangen ze samen?

Voorbeeld voor een webshop:

In een conceptueel model teken je entiteiten (rechthoeken) en relaties (lijnen met beschrijvingen). De details — welke kolommen, welke datatypes, welke sleutels — komen later.

2. Logisch Model

Het logische model vertaalt het conceptuele model naar een gedetailleerdere beschrijving, los van een specifiek databasesysteem. Hier definieer je:

Voorbeeld logisch model voor de Klant-entiteit:

KLANT
├── klant_id        (PK, integer)
├── voornaam        (string, verplicht)
├── achternaam      (string, verplicht)
├── e-mailadres     (string, uniek)
├── geboortedatum   (datum)
└── aanmaakdatum    (datetime)

3. Fysiek Model

Het fysieke model is de implementatie in een specifiek databasesysteem. Hier worden keuzes gemaakt die afhankelijk zijn van de gekozen technologie:

-- Fysiek model in PostgreSQL
CREATE TABLE klanten (
    klant_id        SERIAL PRIMARY KEY,
    voornaam        VARCHAR(100) NOT NULL,
    achternaam      VARCHAR(100) NOT NULL,
    email           VARCHAR(255) UNIQUE NOT NULL,
    geboortedatum   DATE,
    aangemaakt_op   TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT email_format CHECK (email LIKE '%@%.%')
);

-- Index voor snelle lookups op e-mail
CREATE INDEX idx_klanten_email ON klanten(email);

-- Index voor sortering op achternaam
CREATE INDEX idx_klanten_naam ON klanten(achternaam, voornaam);

In het fysieke model houd je rekening met indexen voor snelheid, datatypes die het databasesysteem ondersteunt, partitionering voor grote tabellen en opslaglimieten.

Entity-Relationship Diagrammen (ER-diagrammen)

Een ER-diagram (Entity-Relationship diagram) visualiseert de structuur van een datamodel. Het is de standaard manier om datamodellen te communiceren. Er zijn verschillende notaties, maar de meest gebruikte is de crow's foot (kraaienpoot) notatie.

Symbolen in crow's foot notatie

Symbool Betekenis Voorbeeld
||—|| Exact één Een bestelling heeft exact één klant
||—o| Nul of één Een klant heeft optioneel één primair adres
||—<| Één of meer Een bestelling heeft één of meer bestelregels
||—o< Nul of meer Een klant heeft nul of meer bestellingen

Praktijkvoorbeeld: Webshop ER-diagram

KLANTEN ||--o{ BESTELLINGEN : "plaatst"
BESTELLINGEN ||--|{ BESTELREGELS : "bevat"
PRODUCTEN ||--o{ BESTELREGELS : "staat in"
CATEGORIEËN ||--o{ PRODUCTEN : "groepeert"
ADRESSEN ||--o{ BESTELLINGEN : "verzendadres"
KLANTEN ||--o{ ADRESSEN : "heeft"

Dit eenvoudige diagram communiceert al de kernstructuur: een klant heeft meerdere adressen, plaatst meerdere bestellingen, elke bestelling heeft bestelregels en elke bestelregel verwijst naar een product.

Normalisatie: Data Zonder Redundantie

Normalisatie is het proces om een datamodel te optimaliseren voor integriteit en minimale redundantie. Het is geformaliseerd in "Normale Vormen" (NF). In de praktijk werk je normaal tot en met de derde normale vorm (3NF).

Eerste Normale Vorm (1NF)

Regel: elke cel bevat één waarde, er zijn geen herhalende groepen.

Slecht (niet in 1NF):

bestelling_idklantproducten
1001Jan de VriesLaptop, Muis, Toetsenbord
1002Sara JansenMonitor

Goed (in 1NF):

bestelling_idklantproduct
1001Jan de VriesLaptop
1001Jan de VriesMuis
1001Jan de VriesToetsenbord
1002Sara JansenMonitor

Tweede Normale Vorm (2NF)

Regel: in 1NF én alle niet-sleutelattributen zijn volledig afhankelijk van de volledige primaire sleutel (geen partiële afhankelijkheden).

Probleem: in de 1NF-tabel hierboven staat "klant" bij elke bestelregel hetzelfde. Als Jan zijn naam verandert, moet je drie rijen aanpassen. Dit is een partiële afhankelijkheid: "klant" hangt af van "bestelling_id", niet van "product".

Oplossing — splits in twee tabellen:

-- Tabel 1: Bestellingen
CREATE TABLE bestellingen (
    bestelling_id INT PRIMARY KEY,
    klant_id INT REFERENCES klanten(klant_id)
);

-- Tabel 2: Bestelregels
CREATE TABLE bestelregels (
    bestelregel_id INT PRIMARY KEY,
    bestelling_id INT REFERENCES bestellingen(bestelling_id),
    product_id INT REFERENCES producten(product_id),
    aantal INT NOT NULL DEFAULT 1
);

Derde Normale Vorm (3NF)

Regel: in 2NF én geen transitieve afhankelijkheden (niet-sleutelattributen zijn niet afhankelijk van andere niet-sleutelattributen).

Voorbeeld van een transitieve afhankelijkheid:

-- Problematisch: postcode bepaalt stad, niet de primaire sleutel
KLANT: klant_id → postcode → stad

-- Oplossing: aparte postcodes-tabel
CREATE TABLE postcodes (
    postcode    CHAR(6) PRIMARY KEY,
    stad        VARCHAR(100) NOT NULL,
    provincie   VARCHAR(50)
);

CREATE TABLE klantadressen (
    adres_id    SERIAL PRIMARY KEY,
    klant_id    INT REFERENCES klanten(klant_id),
    straat      VARCHAR(200),
    huisnummer  VARCHAR(10),
    postcode    CHAR(6) REFERENCES postcodes(postcode)
);

Dimensioneel Modelleren: Voor Data Warehouses

Voor analytische omgevingen (data warehouses, rapportages) gebruik je een ander type model: het dimensionele model. Dit is geoptimaliseerd voor leesbaarheid en query-prestaties, niet voor schrijfoperaties.

Feitentabellen en Dimensietabellen

Eigenschap Feitentabel Dimensietabel
Doel Meetwaarden opslaan Context geven aan de meetwaarden
Grootte Groot (miljoenen rijen) Klein (duizenden rijen)
Bevat Getallen en vreemde sleutels Beschrijvende tekst en attributen
Voorbeelden Verkooptransacties, websitebezoeken Klant, Product, Datum, Locatie
Update-frequentie Continu (append-only) Zelden (SCD-logica)

Star Schema

In een star schema staat de feitentabel centraal, met rondom de dimensietabellen. Dit lijkt op een ster — vandaar de naam. Het is eenvoudig te begrijpen en geeft uitstekende queryprestaties.

-- Feitentabel: verkopen
CREATE TABLE feit_verkopen (
    verkoop_id      BIGINT PRIMARY KEY,
    datum_sleutel   INT REFERENCES dim_datum(datum_sleutel),
    klant_sleutel   INT REFERENCES dim_klant(klant_sleutel),
    product_sleutel INT REFERENCES dim_product(product_sleutel),
    winkel_sleutel  INT REFERENCES dim_winkel(winkel_sleutel),
    verkoop_bedrag  DECIMAL(10,2),
    verkoop_aantal  INT,
    korting_pct     DECIMAL(5,2)
);

-- Dimensietabel: datum (essentieel voor tijdanalyses)
CREATE TABLE dim_datum (
    datum_sleutel   INT PRIMARY KEY,  -- bijv. 20250315 voor 15 maart 2025
    datum           DATE NOT NULL,
    dag             INT,
    dag_naam        VARCHAR(20),
    week_nummer     INT,
    maand           INT,
    maand_naam      VARCHAR(20),
    kwartaal        INT,
    jaar            INT,
    is_weekend      BOOLEAN,
    is_feestdag     BOOLEAN,
    feestdag_naam   VARCHAR(100)
);

Snowflake Schema

Bij een snowflake schema worden de dimensietabellen verder genormaliseerd. Producten kunnen bijvoorbeeld een aparte categorietabel hebben. Dit bespaart opslagruimte maar maakt queries complexer door extra joins.

-- Snowflake: product → subcategorie → categorie
CREATE TABLE dim_categorie (
    categorie_id    INT PRIMARY KEY,
    categorie_naam  VARCHAR(100)
);

CREATE TABLE dim_subcategorie (
    subcategorie_id INT PRIMARY KEY,
    naam            VARCHAR(100),
    categorie_id    INT REFERENCES dim_categorie(categorie_id)
);

CREATE TABLE dim_product (
    product_sleutel INT PRIMARY KEY,
    product_naam    VARCHAR(200),
    merk            VARCHAR(100),
    subcategorie_id INT REFERENCES dim_subcategorie(subcategorie_id),
    prijs_huidig    DECIMAL(10,2)
);

Slowly Changing Dimensions (SCD)

Een veelgestelde vraag bij data warehouses: wat doe je als de informatie in een dimensie verandert? Stel dat een klant verhuist. Wil je de historische verkopen koppelen aan het oude of nieuwe adres? Dit heet het Slowly Changing Dimension (SCD) probleem.

SCD Type 1: Overschrijven

De nieuwe waarde vervangt de oude. Geen historiek bewaard. Eenvoudig maar verliest verleden.

UPDATE dim_klant SET stad = 'Rotterdam' WHERE klant_sleutel = 1001;

SCD Type 2: Historiek bewaren (meest gebruikt)

Elke wijziging leidt tot een nieuwe rij met geldigheidsperiode. De meest gebruikte aanpak in analytics.

-- SCD Type 2 structuur
CREATE TABLE dim_klant (
    klant_sleutel       SERIAL PRIMARY KEY,  -- surrogate key
    klant_id_bron       INT NOT NULL,         -- business key
    voornaam            VARCHAR(100),
    achternaam          VARCHAR(100),
    stad                VARCHAR(100),
    geldig_van          DATE NOT NULL DEFAULT CURRENT_DATE,
    geldig_tot          DATE DEFAULT '9999-12-31',
    is_huidig           BOOLEAN DEFAULT TRUE
);

-- Bij verhuizing: sluit oude rij af en maak nieuwe aan
UPDATE dim_klant
SET geldig_tot = CURRENT_DATE - 1, is_huidig = FALSE
WHERE klant_id_bron = 5001 AND is_huidig = TRUE;

INSERT INTO dim_klant (klant_id_bron, voornaam, achternaam, stad)
VALUES (5001, 'Jan', 'de Vries', 'Rotterdam');

Data Modelleren in Power BI

In Power BI gelden dezelfde principes, maar de implementatie is anders. Power BI werkt intern met een kolomgeoriënteerd in-memory model (Vertipaq engine). Een goed Power BI-model volgt altijd het star schema.

Gouden regels voor Power BI datamodellen

-- Datumdimensie genereren in Power Query (M)
let
    StartDatum = #date(2020, 1, 1),
    EindDatum = Date.From(DateTime.LocalNow()),
    AantalDagen = Duration.Days(EindDatum - StartDatum) + 1,
    DatumLijst = List.Dates(StartDatum, AantalDagen, #duration(1, 0, 0, 0)),
    TabelVanDatums = Table.FromList(DatumLijst, Splitter.SplitByNothing()),
    HernoemKolom = Table.RenameColumns(TabelVanDatums, {{"Column1", "Datum"}}),
    DatumType = Table.TransformColumnTypes(HernoemKolom, {{"Datum", type date}}),
    VoegJaarToe = Table.AddColumn(DatumType, "Jaar", each Date.Year([Datum]), Int64.Type),
    VoegMaandToe = Table.AddColumn(VoegJaarToe, "Maand", each Date.Month([Datum]), Int64.Type),
    VoegKwartaalToe = Table.AddColumn(VoegMaandToe, "Kwartaal", each "Q" & Text.From(Date.QuarterOfYear([Datum])), type text),
    VoegWeekdagToe = Table.AddColumn(VoegKwartaalToe, "Dag", each Date.DayOfWeekName([Datum], "nl-NL"), type text)
in
    VoegWeekdagToe

Veelgemaakte Fouten bij Data Modelleren

Na het bespreken van de theorie is het nuttig om de meest voorkomende praktijkfouten te belichten:

Tools voor Data Modelleren

Er zijn diverse tools beschikbaar voor het maken en documenteren van datamodellen:

Tool Type Sterkste punt
dbdiagram.io Gratis, online Snel ER-diagrammen maken met code
Lucidchart Betaald, online Mooie diagrammen, goed voor samenwerking
dbt docs Gratis, code-driven Automatisch documentatie genereren vanuit dbt
DataGrip / DBeaver Database IDE ER-diagram genereren vanuit bestaande database
Erwin / PowerDesigner Enterprise, betaald Volledig beheer van enterprise datamodellen

Conclusie

Data modelleren is geen optionele stap — het is de fundering waarop alle analyses, rapportages en datapipelines worden gebouwd. Begin altijd met een conceptueel model samen met de business, werk toe naar een logisch model en implementeer ten slotte het fysieke model in de gekozen technologie. Gebruik normalisatie om redundantie te vermijden voor transactionele databases, en gebruik het star schema voor analytische omgevingen. Met de juiste aanpak en tools bouw je datamodellen die jarenlang meekunnen.

Deel op LinkedIn
← Terug naar het blogoverzicht
Abdullah Özisik - AI Data Engineer

Over de auteur

Abdullah Özisik — Data Engineer met specialisatie in AI-integratie en MLOps. Expert in het bouwen van intelligente data pipelines die gebruik maken van machine learning en generative AI voor geautomatiseerde data processing en optimalisatie.

Data Modeling: Complete Gids voor Database De… Alle blogs Data Pipeline Best Practices: Complete Gids v…