Combineren van tabellen: join
Contents
1.3. Combineren van tabellen: join#
Databases
De SQL-pagina is een onderdeel van het Database-materiaal. Ook in dit geval maak je de pagina interactief via de “Live code” button, om te experimenteren met eigen varianten van de SQL-opdrachten.
Als we een tabel willen maken met alle inschrijvingen voor een bepaalde event,
met de namen van de leden erin,
dan moeten we combinaties maken van de rijen van de leden-tabel en van de inschrijvingen-tabel.
In een cartesisch product (zie opdrachten) maken we alle combinaties,
maar we zijn hier alleen geïnteresseerd in de combinaties waarvoor geldt:
inschrijvingen.lidnr = leden.lidnr
.
We krijgen dan onderstaande tabel:
Van dit resultaat kunnen we weer de kolommen selecteren (projectie) en de rijen (selectie) die we in het eindresultaat willen zien.
1.3.1. Join in SQL#
%LOAD example.db
1.3.2. Cartesisch product#
Het cartesisch product van twee relaties (tabellen) bevat alle combinaties van de rijen van beide tabellen.
vraag: hoeveel rijen heeft een cartesisch product van twee tabellen met elk 1000 rijen? (1000; 2000; 1.000.000?)
SELECT *
FROM leden, inschrijvingen;
lidnr | voornaam | achternaam | eventnr | lidnr | maaltijd | |
---|---|---|---|---|---|---|
1 | Hans | de Boer | hdebo@ziggo.nl | 1 | 1 | maaltijd A |
1 | Hans | de Boer | hdebo@ziggo.nl | 2 | 1 | maaltijd B |
1 | Hans | de Boer | hdebo@ziggo.nl | 3 | 2 | geen |
1 | Hans | de Boer | hdebo@ziggo.nl | 4 | 3 | maaltijd A |
2 | Marie | Verkerk | marie@verkerk.nl | 1 | 1 | maaltijd A |
2 | Marie | Verkerk | marie@verkerk.nl | 2 | 1 | maaltijd B |
2 | Marie | Verkerk | marie@verkerk.nl | 3 | 2 | geen |
2 | Marie | Verkerk | marie@verkerk.nl | 4 | 3 | maaltijd A |
3 | Jantien | Gerards | jgerards@gmail.com | 1 | 1 | maaltijd A |
3 | Jantien | Gerards | jgerards@gmail.com | 2 | 1 | maaltijd B |
3 | Jantien | Gerards | jgerards@gmail.com | 3 | 2 | geen |
3 | Jantien | Gerards | jgerards@gmail.com | 4 | 3 | maaltijd A |
4 | Marie | Zandstra | marie123@ziggo.nl | 1 | 1 | maaltijd A |
4 | Marie | Zandstra | marie123@ziggo.nl | 2 | 1 | maaltijd B |
4 | Marie | Zandstra | marie123@ziggo.nl | 3 | 2 | geen |
4 | Marie | Zandstra | marie123@ziggo.nl | 4 | 3 | maaltijd A |
1.3.3. Join#
De meeste van deze combinaties zijn zinloos, zoals de inschrijvingen met lidnr 2
, in combinatie met de lid-gegevens van lidnr 1
.
We zijn alleen geïnteresseerd in de rijen waarvan de lidnr’s gelijk zijn.
We selecteren de relevante rijen van het cartesisch product door middel van een WHERE
-voorwaarde.
Dit is een normaal patroon voor een join.
SELECT *
FROM leden lid, inschrijvingen ins
WHERE lid.lidnr = ins.lidnr;
lidnr | voornaam | achternaam | eventnr | lidnr | maaltijd | |
---|---|---|---|---|---|---|
1 | Hans | de Boer | hdebo@ziggo.nl | 1 | 1 | maaltijd A |
1 | Hans | de Boer | hdebo@ziggo.nl | 2 | 1 | maaltijd B |
2 | Marie | Verkerk | marie@verkerk.nl | 3 | 2 | geen |
3 | Jantien | Gerards | jgerards@gmail.com | 4 | 3 | maaltijd A |
We kunnen bovenstaande combinatie (join) van tabellen combineren met andere selectievoorwaarden en met projectie, zoals hieronder:
SELECT lid.voornaam
, lid.achternaam
, lid.email
, ins.eventnr
, ins.maaltijd
FROM leden lid, inschrijvingen ins
WHERE lid.lidnr = ins.lidnr AND lid.voornaam = 'Hans';
voornaam | achternaam | eventnr | maaltijd | |
---|---|---|---|---|
Hans | de Boer | hdebo@ziggo.nl | 1 | maaltijd A |
Hans | de Boer | hdebo@ziggo.nl | 2 | maaltijd B |
(Cartesisch product)
Maak een query voor alle combinaties van de rijen van leden, inschrijvingen en events (Cartesisch product). Hoeveel rijen verwacht je in het resultaat?
(Alle inschrijvingen met volledige gegevens)
Maak een query voor alle inschrijvingen, met daarbij alle gegevens van de leden en van de events.
1.3.3.1. INNER JOIN#
Het cartesisch product heet in SQL de INNER JOIN
.
Het resultaat van deze join is een tabel: deze staat in de query bij het FROM
-deel.
De voorwaarde (meestal: gelijke sleutels) staat bij de join als ON
-voorwaarde.
Op deze manier zijn de join-voorwaarde en de selectie-voorwaarde duidelijk gescheiden:
SELECT lid.voornaam
, lid.achternaam
, lid.email
, ins.eventnr
, ins.maaltijd
FROM leden lid
JOIN inschrijvingen ins
ON lid.lidnr = ins.lidnr
WHERE lid.voornaam = 'Hans';
voornaam | achternaam | eventnr | maaltijd | |
---|---|---|---|---|
Hans | de Boer | hdebo@ziggo.nl | 1 | maaltijd A |
Hans | de Boer | hdebo@ziggo.nl | 2 | maaltijd B |
1.3.3.2. Meer dan 2 tabellen#
We kunnen een join ook over meer dan twee tabellen uitvoeren. Bij elke tabel geven we dan de join-conditie aan.
1.3.4. (De)normalisatie#
De tabellen die we hierboven gebruiken zijn in normaalvorm: Elk basisgegeven komt maar één keer voor. Deze tabellen bevatten geen redundante (overtollige) gegevens. Dat maakt het eenvoudiger om de database te veranderen op een consistende manier.
De volgende tabel (als resultaat van een “join” bewerking) is niet genormaliseerd: je ziet dat dezelfde voornaam, achternaam, email-adres en event-gegevens meerdere malen voorkomen. Dit is een manier van werken die je veel tegenkomt in relationele databases:
basisgegevens breng je onder in genormaliseerde tabellen; veranderingen in de basisgegevens hoef je dan maar op één plek in te voeren;
niet-genormaliseerde tabellen, bijvoorbeeld voor rapportages, reken je uit als dat nodig is.
SELECT *
FROM leden lid, inschrijvingen ins, events evt
WHERE lid.lidnr = ins.lidnr AND evt.eventnr = ins.eventnr;
lidnr | voornaam | achternaam | eventnr | lidnr | maaltijd | eventnr | datum | beschrijving | |
---|---|---|---|---|---|---|---|---|---|
1 | Hans | de Boer | hdebo@ziggo.nl | 1 | 1 | maaltijd A | 1 | 2019-08-21 | Schaaktoernooi Breda |
1 | Hans | de Boer | hdebo@ziggo.nl | 2 | 1 | maaltijd B | 2 | 2019-08-28 | Schaaktoernooi Breda |
2 | Marie | Verkerk | marie@verkerk.nl | 3 | 2 | geen | 3 | 2019-08-28 | Schaaktoernooi Assen |
3 | Jantien | Gerards | jgerards@gmail.com | 4 | 3 | maaltijd A | 4 | 2019-09-15 | Schaaktoernooi Amersfoort |
Meestal gebruik je maar een deel van de kolommen, zoals in de onderstaande projectie:
SELECT lid.voornaam
, lid.achternaam
, evt.beschrijving
, evt.datum
, ins.maaltijd
FROM leden lid, inschrijvingen ins, events evt
WHERE lid.lidnr = ins.lidnr AND evt.eventnr = ins.eventnr;
voornaam | achternaam | beschrijving | datum | maaltijd |
---|---|---|---|---|
Hans | de Boer | Schaaktoernooi Breda | 2019-08-21 | maaltijd A |
Hans | de Boer | Schaaktoernooi Breda | 2019-08-28 | maaltijd B |
Marie | Verkerk | Schaaktoernooi Assen | 2019-08-28 | geen |
Jantien | Gerards | Schaaktoernooi Amersfoort | 2019-09-15 | maaltijd A |