Mermaid ER-diagram-editor
Een entiteit-relatiediagram laat tabellen zien, hun kolommen en de manier waarop ze aan elkaar hangen. Het past wanneer een databaseschema het onderwerp is en de interessante vragen over sleutels en multipliciteit gaan — één op veel, optioneel, of via een koppeltabel. Voor typen met gedrag en overerving is een klassendiagram beter.
Genormaliseerd bestelschema met koppeltabel
Het opvallende deel is `}o--||` bij de bestelregel: zo druk je een veel-op-veelrelatie eerlijk uit, via een koppeltabel met eigen kolommen, in plaats van te doen alsof twee tabellen rechtstreeks aan elkaar hangen. De prijs op de regel bewaren en niet alleen op het product is precies het soort beslissing dat een diagram zichtbaar hoort te maken. Let ook op de aanhalingstekens rond elk relatielabel: in het Nederlands zijn die niet optioneel.
erDiagram
KLANT ||--o{ BESTELLING : "plaatst"
BESTELLING ||--|{ BESTELREGEL : "bestaat uit"
PRODUCT ||--o{ BESTELREGEL : "komt voor in"
KLANT ||--o{ ADRES : "verzonden naar"
BESTELLING ||--o| FACTUUR : "gefactureerd als"
KLANT {
int id PK
string email UK "in kleine letters bewaard"
string naam
string kvk_nummer
datetime aangemaakt
}
BESTELLING {
int id PK
int klant_id FK
string status
decimal totaal
}
BESTELREGEL {
int bestelling_id PK, FK
int product_id PK, FK
int aantal
decimal prijs "prijs op het moment van bestellen"
}
PRODUCT {
int id PK
string artikelnummer UK
string omschrijving
}
ADRES {
int id PK
int klant_id FK
string postcode
}
FACTUUR {
int id PK
string factuurnummer UK
decimal btw_bedrag
}Uitgewerkte voorbeelden
1. Twee entiteiten en één relatie
Elke ER-relatie wil een label na de dubbele punt — anders dan een pijl in een stroomdiagram is dat niet optioneel. Je leest het als een zin: KLANT plaatst BESTELLING.
erDiagram
KLANT ||--o{ BESTELLING : "plaatst"2. Kolommen toevoegen
Elke attribuutregel is `type naam` en beide delen zijn verplicht. `PK`, `FK` en `UK` markeren sleutels; de tekst tussen aanhalingstekens aan het eind is een opmerking bij de kolom.
erDiagram
KLANT ||--o{ BESTELLING : "plaatst"
KLANT {
int id PK
string email UK
string naam
}
BESTELLING {
int id PK
int klant_id FK
datetime geplaatst "in UTC"
}3. Een multipliciteit die iets zegt
De twee tekens die het dichtst bij een entiteit staan zijn haar multipliciteit. Dit voorbeeld zegt dat een bestelling minstens één regel moet hebben, maar dat een klant helemaal geen bestelling hoeft te hebben: een echte beperking die het schema hoort af te dwingen en het diagram hoort te tonen.
erDiagram
KLANT ||--o{ BESTELLING : "plaatst"
BESTELLING ||--|{ BESTELREGEL : "bestaat uit"
BESTELREGEL }o--|| PRODUCT : "verwijst naar"4. Veel op veel via een koppeltabel
Mermaid kan een rechtstreekse veel-op-veelrelatie tekenen, maar in het schema bestaat die vrijwel nooit: eronder ligt een koppeltabel. Die tekenen is eerlijker en geeft ruimte aan de kolommen die bij de relatie zelf horen.
erDiagram
STUDENT ||--o{ INSCHRIJVING : "schrijft zich in voor"
CURSUS ||--o{ INSCHRIJVING : "wordt gegeven via"
INSCHRIJVING {
int student_id PK, FK
int cursus_id PK, FK
datetime inschrijfdatum
string cijfer "leeg tot het tentamen"
}
STUDENT {
int id PK
string achternaam
}
CURSUS {
int id PK
string code UK
}5. Relaties naar zichzelf
Een tabel kan een relatie met zichzelf hebben: een aansturingslijn, een categorieboom, een reactiedraad. Het relatielabel telt hier zwaarder dan gewoonlijk, want beide uiteinden zijn dezelfde entiteit.
erDiagram
MEDEWERKER ||--o{ MEDEWERKER : "geeft leiding aan"
MEDEWERKER {
int id PK
int leidinggevende_id FK "leeg voor de directie"
string achternaam
string functie
}Overzicht van de ER-diagram-syntaxis
De multipliciteit schrijf je met twee tekens aan elk uiteinde van de relatie en je leest hem van binnen naar buiten. Het linkerpaar beschrijft de linkerentiteit, het rechterpaar de rechter.
| Syntaxis | Betekenis |
|---|---|
| erDiagram | Opent het diagram. Hoofdlettergevoelig: `erdiagram` werkt niet. |
| A ||--o{ B : "label" | Relatie. Het label is verplicht. |
| || | Precies één. |
| o| | Nul of één. |
| }| | Één of meer. |
| }o | Nul of meer. |
| -- | Identificerende relatie — doorgetrokken lijn. |
| .. | Niet-identificerende relatie — onderbroken lijn. |
| A { ... } | Attribuutblok van entiteit A. |
| int id PK | Attribuut: eerst het type, dan de naam, dan de eventuele sleutelmarkering. |
| PK / FK / UK | Primaire, refererende, unieke sleutel. |
| int id PK, FK | Meerdere sleutelmarkeringen, gescheiden door een komma. |
| string email "opmerking" | De tekst tussen aanhalingstekens aan het eind is een opmerking bij de kolom. |
| A ||--o{ B : "hoort bij" | Aanhalingstekens zijn VERPLICHT zodra het label een spatie bevat. Zonder breekt het af bij de eerste spatie en wordt elk overgebleven woord een spookentiteit. |
De zes fouten die een ER-diagram slopen
ER heeft de strengste grammatica van de zes typen: wat in andere diagrammen doorkomt, wordt hier ronduit geweigerd. Maar het heeft ook een stille fout waar je in het Nederlands bijzonder makkelijk in loopt. Alles nagemaakt op Mermaid 11.12.2.
Wat je ziet
Het tekent, het label is afgekapt en er staan entiteiten in het diagram die je niet geschreven hebt
Waarom
Het relatielabel bevat een spatie en heeft geen aanhalingstekens. Dit is de fout die in het Nederlands het meeste dwarszit, want onze relatiewerkwoorden nemen bijna altijd een voorzetsel: «hoort bij», «komt voor in», «verzonden naar». Gemeten: `KLANT ||--o{ BESTELLING : hoort bij` meldt geen enkele fout, kort het label in tot «hoort» en maakt een lege entiteit met de naam «bij». Bij drie woorden ontstaan er twee spookentiteiten. Twee tabellen tekenen als vier rechthoeken en niets waarschuwt je — behalve dat de viewBox van 128 naar 375 pixels springt.
Oplossing
Zet elk label met een spatie tussen aanhalingstekens. In het Nederlands betekent dat praktisch altijd; het is makkelijker om er een regel van te maken dan het elke keer af te wegen.
erDiagram
KLANT ||--o{ BESTELLING : hoort bijerDiagram
KLANT ||--o{ BESTELLING : "hoort bij"Wat je ziet
Parse error die eindigt op: Expecting 'COLON', 'STYLE_SEPARATOR', got 'NEWLINE'
Waarom
Een relatie zonder label. Anders dan bij een pijl in een stroomdiagram zijn de dubbele punt en het label verplicht: zonder houdt de regel gewoon te vroeg op.
Oplossing
Voeg een dubbele punt en een werkwoordsvorm toe, tussen aanhalingstekens als er een spatie in zit.
erDiagram
KLANT ||--o{ BESTELLINGerDiagram
KLANT ||--o{ BESTELLING : "plaatst"Wat je ziet
Parse error die eindigt op: got 'UNICODE_TEXT'
Waarom
Een ongeldig multipliciteitsteken. Alleen `||`, `o|`, `}|` en `}o` zijn correct (en hun spiegelvormen); al het andere valt om. `oo` is de klassieke tikfout, uit de aanname dat de notatie symmetrisch is.
Oplossing
Gebruik een van de vier paren. `||--o{` — precies één naar nul of meer — dekt de meeste refererende sleutels.
erDiagram
KLANT ||--oo{ BESTELLING : "plaatst"erDiagram
KLANT ||--o{ BESTELLING : "plaatst"Wat je ziet
Parse error die eindigt op: Expecting 'ATTRIBUTE_WORD', got 'BLOCK_STOP'
Waarom
Een attribuut heeft wel een naam maar geen type. ER-attributen schrijf je als `type naam`, en het type is niet optioneel — wat mensen verrast die uit schemaloze databases komen.
Oplossing
Geef elk attribuut een type. Verzin er een als het echte schema het niet heeft: `string`, `int`, `json`.
erDiagram
KLANT {
email
}erDiagram
KLANT {
string email
}Wat je ziet
Parse error die eindigt op: Expecting 'NON_IDENTIFYING', 'IDENTIFYING', got 'UNICODE_TEXT'
Waarom
De lijn tussen de twee multipliciteitstekens is verkeerd. Hij moet precies twee tekens lang zijn: `--` voor een identificerende relatie of `..` voor een niet-identificerende. Eén streepje is geen verkorte vorm van `--`, maar een syntaxisfout.
Oplossing
Schrijf `--` of `..` tussen de multipliciteitsparen.
erDiagram
KLANT ||-o{ BESTELLING : "plaatst"erDiagram
KLANT ||--o{ BESTELLING : "plaatst"Wat je ziet
De multipliciteit tekent, maar beschrijft de omgekeerde beperking
Waarom
De twee tekens die het dichtst bij een entiteit staan horen bij precies die entiteit, en ze omgekeerd lezen is heel makkelijk. `KLANT ||--o{ BESTELLING` zegt dat één klant nul of meer bestellingen heeft. Draai het om naar `KLANT }o--|| BESTELLING` en je beweert dat elke klant bij precies één bestelling hoort, wat nergens op slaat — en het tekent zonder het minste bezwaar.
Oplossing
Lees van binnen naar buiten: de tekens die KLANT raken beschrijven hoeveel klanten er zijn, niet hoeveel bestellingen.
erDiagram
KLANT }o--|| BESTELLING : "plaatst"erDiagram
KLANT ||--o{ BESTELLING : "plaatst"Aantekeningen over het tekenen
Gemeten op Mermaid 11.12.2, de versie die deze site gebruikt.
De indeling wordt bepaald door de relaties, niet door het aantal entiteiten
Een ketting van entiteiten die elk aan de volgende hangen tekent als een hoge kolom: veertig entiteiten geven een viewBox van ongeveer 116×7315, tegen 116×470 bij drie. Maar dezelfde veertig entiteiten die allemaal aan één centrale tabel hangen geven iets veel breders en lagers. Dit is het enige diagramtype hier waarin de vorm van je gegevens de vorm van het plaatje meer verandert dan zijn omvang, dus een schema dat niet past los je vaker op door te veranderen welke relaties je tekent dan hoeveel.
In het Nederlands vraagt bijna elk label aanhalingstekens
Het is de herhaling waard, want dit is de duurste stille fout op deze pagina. Engelse relatielabels kunnen uit één woord bestaan — places, contains, references — waardoor de aanhalingstekens in Engelse documentatie op een versiersel lijken. In het Nederlands nemen de meeste een voorzetsel en vallen ze zonder aanhalingstekens uit elkaar. Vuistregel: zet het label altijd tussen aanhalingstekens en denk er verder niet meer over na.
Entiteitsnamen zijn hoofdlettergevoelig, samenstellingen werken prima
`KLANT` en `klant` zijn twee verschillende entiteiten, en ze allebei in één diagram noemen levert zonder waarschuwing twee rechthoeken op. De hoofdlettersconventie dwingt Mermaid niet af, maar het loont om hem aan te houden juist omdat hij een per ongeluk kleingeschreven verwijzing zichtbaar maakt. Lange Nederlandse samenstellingen werken zonder bezwaar als entiteits- en kolomnaam — `BESTELREGEL` en `factuurnummer` zijn getoetst — en anders dan in een label is er hier geen breedteprobleem, want een entiteitsblok schaalt met zijn kolommen.
De grammatica is de strengste van de zes typen
Relatielabels zijn verplicht, attribuuttypen ook, en de multipliciteitstekens vormen een gesloten verzameling. Vergeleken met gantt, waar vrijwel alles tekent en de fouten zwijgen, valt ER vroeg en luid om. Dat is een voordeel: als een ER-diagram getekend is, is de kans behoorlijk groot dat het het diagram is dat je bedoelde — met de duidelijke uitzondering van labels zonder aanhalingstekens.
Labels zijn HTML, dus de PNG-export tekent opnieuw
De attribuuttabellen van entiteiten worden binnen een `<foreignObject>` in de SVG getekend, dus browsers kunnen ze niet rechtstreeks op een canvas rasteren. De PNG-export van deze site gaf vroeger stilzwijgend een SVG-bestand terug; nu tekent hij het diagram eerst opnieuw met gewone SVG-tekstlabels en levert een correcte PNG op volle grootte, met een nauwelijks merkbaar andere zetwijze.
Wanneer een ander diagram beter past
Heb je overerving, interfaces of methoden nodig, dan is dit het verkeerde diagram: ER kent geen van die begrippen. Gebruik een klassendiagram en aanvaard dat het je code modelleert en niet je tabellen.
Is het schema groot, dan wordt een ER-diagram van het geheel een muurposter die niemand leest. Teken de vijf tabellen die raken aan wat je op dat moment uitlegt en laat de rest buiten beeld; een diagram is een betoog, geen inventarislijst.
En is de echte vraag hoe gegevens tussen systemen stromen in plaats van hoe ze bewaard worden, dan beantwoordt een stroomdiagram met een subgrafiek per systeem die vraag, en een ER-diagram niet.
Andere diagramtypen
Geschreven door Dominik Malsch · Laatst bijgewerkt: