You are on page 1of 35

Dictaat databases en SQL

-versie augustus 2016


INHOUD
1. Inleiding ........................................................................................................................................................... 4
2. EER-model ....................................................................................................................................................... 5
2.1 Het nut ................................................................................................................................................... 5
2.2 De notatie .............................................................................................................................................. 5
2.3 Een voorbeeld ........................................................................................................................................ 6
2.3.1 De entiteiten ..................................................................................................................................... 7
2.3.2 De relaties ......................................................................................................................................... 7
2.3.3 De attributen ..................................................................................................................................... 7
2.4 Het EER-model ....................................................................................................................................... 7
2.4.1 Kardinaliteit ....................................................................................................................................... 7
2.4.2 Subtypering ....................................................................................................................................... 8
3. Databaseontwerp............................................................................................................................................ 9
3.1 Model en ontwerp ................................................................................................................................. 9
3.2 Transformatie ........................................................................................................................................ 9
3.3 Notatie ................................................................................................................................................... 9
3.4 Relaties transformeren ........................................................................................................................ 10
3.5 Recursieve relaties ............................................................................................................................... 11
3.6 Subtyperingen transformeren ............................................................................................................. 12
4. Logische expressies ....................................................................................................................................... 14
4.1 Een logisch voorbeeld .......................................................................................................................... 14
4.2 Logische expressies.............................................................................................................................. 14
4.3 Expressies vereenvoudigen ................................................................................................................. 15
4.4 Waarheidstabellen .............................................................................................................................. 15
5. Constraints .................................................................................................................................................... 17
5.1 Uitleg ................................................................................................................................................... 17
5.2 Soorten constraints ............................................................................................................................. 17
5.2.1 Attribuut constraints ....................................................................................................................... 18
5.2.2 Tupel constraints ............................................................................................................................. 18
5.2.3 Tabel constraints ............................................................................................................................. 18
5.2.4 Database constraints ....................................................................................................................... 19
5.2.5 Dynamische constraints .................................................................................................................. 19
5.3 Constraints in SQL ................................................................................................................................ 19
5.4 Constraints in het ontwerp .................................................................................................................. 19
6. DDL en DML................................................................................................................................................... 21
6.1 Een tabel aanmaken ............................................................................................................................ 21
6.2 Een tabel aanpassen ............................................................................................................................ 22
6.3 Een tabel verwijderen .......................................................................................................................... 22
6.4 Data manipulatie ................................................................................................................................. 23
6.5 Transacties ........................................................................................................................................... 23
7. Geavanceerde SQL ........................................................................................................................................ 25
7.1 Gegevens selecteren ........................................................................................................................... 25
7.2 Rekenen en groeperen ........................................................................................................................ 25
7.3 Tabellen samenvoegen ........................................................................................................................ 26
7.3.1 INNER JOIN ...................................................................................................................................... 27
7.3.2 OUTER JOIN ..................................................................................................................................... 28
7.3.3 FULL OUTER JOIN ............................................................................................................................ 29
7.4 Recursieve JOIN ................................................................................................................................... 29
7.5 Gecorreleerde subquery ...................................................................................................................... 30
8. T-SQL ............................................................................................................................................................. 32
8.1 Uitleg ................................................................................................................................................... 32
8.2 Procedures en functies ........................................................................................................................ 32
8.3 Triggers ................................................................................................................................................ 33
8.4 Cursors ................................................................................................................................................. 34
augustus 2016

1. Inleiding
Bij databases begint het bij een vraag om informatie. Hoe en waar ga je die opslaan? Allereerst zal je de
wensen van de klant moeten vast leggen alvorens een oplossing te komen. Daarna kun je het technische plan
maken en tot uitvoering brengen. Dit kan soms heel erg complex worden. Vandaar dat een goede
voorbereiding essentieel is. Denk daarbij aan het maken van een analyse en een goed ontwerp.

In dit dictaat worden alle relevante zaken die nodig zijn omtrent databases en SQL kort behandeld. We
beginnen bij het EER-model en gaan vanuit daar verder met het databaseontwerp (DBO), logische
expressies en constraints, DDL en DML, SQL en tot slot T-SQL. In dit laatste gedeelte kun je informatie vinden
over het programmeren in de database met T-SQL. Daar worden variabelen, if-statements, loops, functies en
procedures, triggers en cursors in behandeld.

Let op: Dit dictaat is in ontwikkeling. Mocht je er onduidelijkheden of zelfs fouten in aantreffen laat het de
huidige vakeigenaar dan weten. Hij of zij zal het dan rechtzetten. Bij voorbaat dank voor je hulp! Samen maken
we er een goed te lezen dictaat van.

Succes en veel plezier!

-4-
augustus 2016

2. EER-model
Een klant brengt graag in al zijn enthousiasme het verhaal over van zijn probleem of de opdracht. Dit is vaak
een onsamenhangend verhaal waarin hij niet goed weet wat er precies gedaan moet worden. Om daar
structuur in te krijgen kan er na het gesprek een model gemaakt worden van het domein van de klant. In zo’n
model worden alle relevante zaken opgenomen die belangrijk kunnen zijn voor de technische invulling van de
opdracht. Die technische invulling komt later wel, eerst het model!

In dit document gebruiken we daar ER-modellen voor. In dit hoofdstuk staat we kort stil bij de onderwerpen
die daarbij een rol spelen.

2.1 Het nut


Zoals zojuist al is aangegeven is het ER-model een variant van vele andere mogelijke notaties voor het model.
Welke notatie je ook kiest, het is altijd goed om eerst een model te maken van de probleemstelling. Dit heeft
een aantal voordelen:
• Een model is flexibel waardoor het eenvoudig en snel aan te passen en uit te breiden is.
• Een model is eenvoudig te begrijpen, ook zonder technische voorkennis.
• Een model geeft een goed overzicht van de aspecten die een rol spelen in het domein van de klant.
• Een model kan als basis dienen voor ontwerpen die later gemaakt gaan worden.

Iets op (digitaal) papier aanpassen is gemakkelijker dan in code. Wellicht nu nog niet, nu alles nog
overzichtelijk is in deze fase van je studie. Er komt echter en dag waarop je zelf ook terug kijkt naar je code en
dan graag een visuele houvast had willen hebben, bijvoorbeeld een model.

Er zijn eigenlijk maar 3 (of 4) verschillende vormen nodig bij het tekenen van een ER-model: vierkanten, ruiten
en ellipsen (en lijnen). Dat is eenvoudig te overzien en te bevatten. Ook voor iemand met gewoon gezond
verstand, maar zonder een technische achtergrond of ervaring in de ICT.

De klant kan na afloop van de eerste meeting over de opdracht snel zijn verhaal terugzien in het model. Zo kan
hij snel verifiëren of het goed is overgekomen. Mocht er iets missen, dan kan dat snel doorgegeven worden
een eenvoudig aangepast worden voor een update. Zo kun je dus in een vroeg stadium feedback krijgen over
jouw beeld van de opdracht.

Het model zal ook als inspiratie dienen voor de technische ontwerpen die gemaakt dienen te worden voor de
software. Het DBO (zie volgende hoofdstuk) maar ook het klassendiagram zouden hier van afgeleid kunnen
worden. Echter, let daarbij op dat het niet overgenomen moet worden! Een model is geen DBO en al helemaal
geen klassendiagram. Het hoeft dus niet zo te zijn dat elke entiteit letterlijk terug te vinden is in het DBO. Een
entiteit zou een klasse kunnen worden, maar dat moet niet. Het zou heel goed kunnen dat het niet nodig is in
de software. Denk daar dus in de ontwerpfase goed over na!

2.2 De notatie
Zoals gezegd bestaat het ER-model uit 3 basisvormen. Entiteiten zijn vierkanten, attributen van entiteiten
worden weergegeven als een ellips en relaties tussen entiteiten zijn ruiten. De verbindingen teken je met een
lijn tussen de verschillende componenten.

Entiteiten zijn ‘dingen’ die belangrijk zijn in het verhaal. Ze worden altijd in enkelvoud aangegeven. Denk
bijvoorbeeld aan een klant en een factuur. Deze ‘dingen’ hebben meestal eigenschappen die op hun beurt ook
weer belangrijk zijn in het geheel. Zo heeft een klant een naam, adres en een rekeningnummer en een factuur
heeft een factuurnummer en een datum. Dit noemen we attributen van de entiteit. Er bestaan ook onderlinge
-5-
augustus 2016

relaties tussen verschillende entiteiten. In dat geval zet je een ruit tussen de twee entiteiten en verbind elke
entiteit met de ruit om de onderlinge relatie aan te geven.

Er zijn drie verschillende soorten relaties, namelijk 1-op-1, 1-op-veel en veel-op-veel. In onderstaande tabel
vind je per relatie een voorbeeld van entiteiten die zo’n relatie zouden kunnen hebben samen en een
bijbehorende uitleg.

Soort relatie Voorbeeld entiteiten Uitleg


1-op-1 Bestelling en factuur. Bij elke bestelling hoort 1 factuur en die ene factuur hoort maar
bij 1 bestelling.
1-op-veel Klant en bestelling. Een klant kan meerdere bestellingen plaatsen, maar de bestelling
wordt altijd maar door 1 klant geplaatst.
Veel-op-veel Bestelling en product. Er kunnen meerdere producten worden besteld per bestelling,
maar die producten kunnen ook meerdere keren besteld worden.

Laten we naar een voorbeeld kijken.

2.3 Een voorbeeld


Hieronder zie je een voorbeeld van een ER-model.

Figuur 1: Een voorbeeld van een ER-model.

In figuur 1 zie je een voorbeeld van een ER-model over projecten waar medewerkers aan werken voor een
bepaalde klanten. Hieronder bespreken we stuk voor stuk alle aspecten van dit model.

-6-
augustus 2016

2.3.1 De entiteiten
Het voorbeeld ER-model uit figuur 1 kent drie entiteiten. Deze drie zijn klant, project en medewerker. De naam
van een entiteit is altijd in enkelvoud zoals je misschien al is opgevallen.

2.3.2 De relaties
Elke project wordt voor een specifieke klant gedaan. Er kunnen meerdere projecten voor een klant worden
gedaan. Op elk project kunnen meerdere medewerkers werken. Een medewerker kan aan meerdere projecten
werken. Zoals je ook kunt zien in het model is de functie die een medewerker vervult bij een bepaald project
een attribuut van de relatie. De functie kan namelijk door meerdere personen vervuld worden en een
medewerker kan op elk project een andere functie hebben.

2.3.3 De attributen
Elke entiteit heeft een attribuut in dit voorbeeld. Dat is echter niet verplicht voor een entiteit. Zo kan het
voorkomen dat een entiteit geen attributen heeft in het model. De attributen die zijn onderstreept zijn
identificerend. Dat betekent dat met dat attribuut een specifieke entiteit kan worden aangewezen. Zo kun je
bijvoorbeeld aan de hand van het KVK nummer een specifieke klant aanwijzen. Er is er maar 1 met dat
nummer. Met het adres van een klant is ook iets geks aan de hand. Dat attribuut is dubbel omcirkeld. Dat
betekent dat dit attribuut bestaat uit meerdere gegevens. Zo kan een adres bestaan uit een straat,
huisnummer en een woonplaats. Echter, een postcode met huisnummer kan ook voldoende zijn.

2.4 Het EER-model


Het ER-model kent ook een uitbreiding, namelijk het “Enhanced” of “Extended” ER-model. In het kort noemen
we dat het EER-model. Hieronder zie je een voorbeeld van een EER-model als aanvulling op de medewerker-
entiteit uit het eerdere voorbeeld.

Waarschijnlijk vallen je een aantal nieuwe


dingen op. Zo is er een relatie van en naar
dezelfde entiteit. Dit kan en mag ook in een
gewoon ER-model. Deze relatie zegt dat
een medewerker onder 1 specifieke andere
medewerker kan werken. Je kunt dit zien
als zijn baas. Die persoon kan dus weer
meerdere medewerkers onder zich
hebben.

Ook loopt er een dubbele lijn van een


relatie naar een entiteit. Dit is wel een
specifieke uitbreiding die bij het EER-model
wordt gebruikt. Dit gaat over de
kardinaliteit van een relatie. Figuur 2: een deel van een EER-model.

Tot slot zijn er blijkbaar twee specifieke medewerkers, namelijk de consultant en de accountmanager. Dit zijn
subtypes van de medewerker. Deze uitbreiding op het ER-model heet dan ook subtypering. Deze twee
uitbreidingen, kardinaliteit en subtypering wordt hieronder kort beschreven.

2.4.1 Kardinaliteit
Elke relatie heeft een kardinaliteit. We hebben tot nu toe drie type relaties gezien: 1-op-1, 1-op-veel en veel-
op-veel. Echter deze kunnen beide kanten op ook optioneel of verplicht zijn. De lijn van een relatie kan enkel
of dubbel worden getekend. Wanneer deze enkel is, is de relatie optioneel. De entiteit kan maar moet niet
perse deelnemen in de relatie. Als er een dubbele lijn wordt gebruikt is de relatie verplicht. De entiteit moet
-7-
augustus 2016

dan minstens 1 keer deelnemen aan de relatie. In het voorbeeld van figuur 2 betekent het dat elke consultant
ten minste 1 specialisme moet hebben. Niet elke specialisme is toegerekend aan een consultant.
Zie het volgende voorbeeld.
Figuur 3: Een medewerker en zijn afdeling.
In figuur 3 zie je dat een medewerker
verplicht op 1 afdeling werkt. Uiteraard
kan het zo zijn dat een medewerker op
meer dan 1 afdeling tegelijk werkt. Echter,
dit model zegt dat in dit geval dat niet zo
is. Elke medewerker werkt op verplicht 1
afdeling.

Elke afdeling heeft optioneel meerdere


mensen daar werken. Dat is natuurlijk een
beetje gek. Wat is nou een afdeling
zonder medewerkers? Bij twijfel kun je
dat het beste navragen. Klopt het dat er afdelingen zijn waar, misschien tijdelijk, geen medewerkers werken?
Als degene die antwoord kan geven op dat soort vragen niet beschikbaar dan kun je het beste een aanname
doen. In dit geval kun je de aanname maken dat er soms geen medewerkers op een afdeling werkzaam zijn.
Onderbouw altijd je keuzes!

2.4.2 Subtypering
De subtypering gebruik je overal waar je wat complexere entiteiten wilt modelleren zonder daar heel veel
dubbel voor te moeten noteren. In het EER-model uit figuur 2 zie je eigenlijk 3 soorten medewerkers. Er zijn
consultants, accountmanagers en “gewone” medewerkers. Elk van deze drie soorten hebben de eigenschapen
van een medewerker. Dat betekent dat elke medewerker, consultant en accountmanager een “werkt onder”-
relatie heeft. Iedereen kan dus een baas hebben, wat natuurlijk ook klopt in het echt. Wanneer de entiteit nog
attributen had gehad zouden deze ook door alle drie de entiteiten en sub-entiteiten worden gedeeld.

Deze subtypering noemen we ook wel een is-een-relatie. Dat komt omdat je het altijd kunt uitspreken als “een
consultant is een medewerker” en ook “een accountmanager is een medewerker”. Wanneer dat in jouw
model niet zo werkt moet je nog eens goed naar je oplossing kijken.

Het voordeel van de subtypering is dat we dus niet alle attributen en relaties die een medewerker heeft ook bij
de consultant en accountmanager moeten zetten. Die krijgen ze ook, want het zijn medewerkers. Bijkomend
voordeel is dat we bij de subtypes kunnen afwijken van de standaard medewerker-entiteit. Zo heeft elke
accountmanager een bonus per account die hij binnen weet te halen. Een “gewone” medewerker en een
consultant heeft die bonus niet, maar de accountmanager wel. Consultants hebben specialismen waar
accountmanagers en “gewone” medewerkers dat niet hebben.

Tot slot kun je nog aangeven of de subtypering verplicht is of niet. Zo kan het zijn dat elke medewerker een
consultant of een accountmanager moet zijn en niet “gewoon” een medewerker is. Dan is de subtypering
verplicht. Dat geef je net als bij de kardinaliteit aan met een dubbele lijn.

De subtypering kun je vergelijken met het principe van overerving binnen het object-georiënteerd
programmeren.

-8-
augustus 2016

3. Databaseontwerp
Nadat het model is opgesteld en de klant zijn goedkeuring heeft gegeven kan er worden nagedacht over de
technische invulling van de opdracht. Ook daar moet goed over worden nagedacht. In dit dictaat gaan we er
natuurlijk vanuit dat er een database nodig zal zijn, maar dat hoeft natuurlijk lang niet altijd het geval te zijn.
Sommige zaken kunnen prima in een file worden opgeslagen of hebben geen persistentie nodig.

Als eerste moet er een keus worden gemaakt voor het type en merk database. In veel gevallen zal er voor een
relationele database gekozen worden, maar NoSQL databases zijn sterk in opkomst met de steeds groter
wordende informatiestroom die we Big Data noemen. In ons geval gaan we het hebben over relationele
databases. Dat heeft alles met informatie te maken die onderlinge een sterke relatie met elkaar hebben. Denk
daarbij bijvoorbeeld aan grote betaal- en banksystemen.

Het merk is ook belangrijk, want elke fabrikant heeft zo net weer zijn eigen manier van doen. De concepten
zijn overal hetzelfde, maar de invulling ervan niet altijd. In ons geval hebben we voor Microsoft SQL Server
gekozen, maar andere relationele databases zijn bijvoorbeeld die van Oracle, MySQL, PostgreSQL en DB2.

3.1 Model en ontwerp


“Waarom eerst een model maken wanneer je ook direct het ontwerp kunt maken”, is vaak de vraag. Een
model maak je als praatplaatje voor de klant(vertegenwoordiger) en het ontwerp voor de ontwikkelaar van de
database. Hieronder zie je een overzicht van de verschillen tussen een model en een ontwerp.

• Een model heeft mogelijk subtyperingen.


• Een model heeft mogelijk één of meerdere N:M relaties.
• Een DBO heeft dat allemaal niet.
• Een DBO kan bijvoorbeeld wel koppeltabellen hebben.
• Een DBO heeft ID's, foreign keys en datatypes.
• Een DBO kan rechtstreeks omgezet worden in SQL.

Alle punten zijn belangrijk, maar zeker het laatste punt. Een model is niets meer dan een snelle schets van de
meest belangrijke aspecten van de opdracht voor een klant. Een ontwerp is een gedetailleerde tekening van
hetgeen gemaakt moet gaan worden in code. Dit kan dus direct omgezet worden in SQL commando’s om de
database aan te maken.

3.2 Transformatie
Om van een EER-model tot een DBO te komen zijn bepaalde stappen nodig. Hieronder worden de
verschillende stappen genoemd.

1. Maak voor elke entiteit een tabel.


2. Transformeer alle standaard relaties (1:1, 1:N en N:M).
3. Transformeer recursieve relaties.
4. Transformeer subtyperingen.

We kijken eerst naar de algemene notatie en daarna naar de omzetting van model naar ontwerp.

3.3 Notatie
We hanteren in dit document een vaste notatie voor het DBO. Op de volgende pagina zie je een voorbeeldje
van een tabel. De naam van de tabel staat bovenaan, in de eerste rij van de tabel. In dit geval gaat het om
een tabel “Persoon”. Daarna volgens de attributen van de tabel. Bij deze tabel zijn dat er vijf. Bovenaan
staat altijd de
-9-
augustus 2016

primaire sleutel (Engels: primaire key, PK), daarna de vreemde Figuur 4: Een voorbeeld van een tabel in een DBO.
sleutels (Engels: Foreign Key, FK) en dan de overige attributen.
Gegevens die uniek moeten blijven binnen een kolom worden
met de letter U gemarkeerd van UNIQUE. Gegevens die
leeggelaten mogen worden noemen we nullable en worden met
de letter N gemarkeerd.

De PK, FK, U en N zijn vormen van constraints. Daar volgt in een


later hoofdstuk meer informatie over. Deze vier constraints kun
je in de eerste kolom van een tabelontwerp aangeven. Je kunt ze ook combineren om zo bijvoorbeeld een
nullable doch uniek attribuut te ontwerpen. Ze de constraints dan komma-gescheiden in het ontwerp. Hier
volgt verderop nog een voorbeeld van.

In de linker-kolom van het DBO staan de constraints, in het midden de attributen en rechts de datatypes. De
datatypes zijn types die gebruikt kunnen worden voor de gekozen database. In ons geval MSSQL, dus de types
in het voorbeeld hierboven zijn specifiek voor MSSQL.

3.4 Relaties transformeren


Bestudeer het volgende EER-model.

Figuur 5: Een ERR-model over orders en producten.

Je ziet in dit voorbeeld een veel-op-veel-relatie tussen order en product. Een order heeft één of meerdere
producten en een product staat optioneel op veel orders. Een veel-op-veel-relatie werk je altijd op dezelfde
manier uit, namelijk met behulp van een koppeltabel (zie figuur 6). Het attribuut aantal kan dan ook mooi in
die nieuwe tabel worden opgenomen. OrderRegel lijkt een mooie naam voor deze tabel. Wat je vaak ziet is een
combinatie van de twee tabellen, in dit geval bijvoorbeeld Order_Product.

Zoals je ziet aan de koppeltabel zijn er twee vreemde sleutels (FK) en is er één gecombineerde primaire sleutel
(PK). Dat wil zeggen dat de combinatie van OrderID en ProductID altijd uniek is.

-10-
augustus 2016

Figuur 6: Een databaseontwerp van orders en producten.

Overige relaties werk je op een soortgelijke manier uit. Bij een 1:N relatie zet je de vreemde sleutel aan de
“veel-kant”. Die tabel gaat dus verwijzen naar één andere regel in de andere tabel. Een 1:1 relatie werk je uit
als een 1:N relatie, maar dan met een UNIQUE constraint op de vreemde sleutel. Zo voorkom je dat er
meerdere verwijzingen naar dezelfde regel kunnen ontstaan.

3.5 Recursieve relaties


Recursieve relaties zijn speciale relaties waarbij er een tabel aan zichzelf wordt gekoppeld. In figuur 7 zie je een
voorbeeld van een EER-model waar een student-tabel met zichzelf is verbonden.

Figuur 7: Een student geeft en ontvangt 1 of meerdere peer reviews.

Een recursieve relatie werk je op precies dezelfde manier uit als bij een normale, niet-recursieve relatie. In het
geval van de studenten met peer reviews hebben we te maken met een veel-op-veel relatie. In dat geval
krijgen we, net als in het vorige voorbeeld, een koppeltabel. Deze bevat dan ook twee vreemde sleutels, alleen
verwijzen deze allebei naar dezelfde primaire sleutel van dezelfde tabel.. In figuur 8 zie je het resultaat van
bovenstaand EER-model.

-11-
augustus 2016

Figuur 8: Een uitgewerkte veel-op-veel recursieve relatie.

3.6 Subtyperingen transformeren


Waar het bij alle vormen van relaties heel duidelijk is wat je er mee kunt doen om deze om te zetten in een
databaseontwerp, is dat voor subtyperingen een stuk lastiger. Kort gezegd is er geen standaard manier om een
subtypering te transformeren naar een DBO. Er zijn echter wel een aantal mogelijkheden. Die gaan we
bespreken, aan de hand van een voorbeeld, zie figuur 9.

Figuur 9: Een klein voorbeeld met een subtypering.

Grofweg zijn er vier mogelijkheden voor het uitwerken van een subtypering:

1. Voeg alle super- en subtypes samen tot één tabel.


2. Maak een tabel voor het hoofdtype en een voor de discriminator.
3. Elke combinatie tussen hoofd- en subtype vormt een nieuwe tabel.
4. Elke entiteit (super- en sub-) worden per stuk in een nieuwe tabel getransformeerd.

Bij optie 1 zou je een grote tabel krijgen die je dan waarschijnlijk Medewerker zou noemen. De attributen voor
accountmanager zijn leeg wanneer het om een consultant gaat en vice versa. Je hebt nog 1 extra attribuut
nodig om het onderscheid tussen de twee subtypes te kunnen maken om te zien wat voor een soort
medewerker het betreft.

Optie 2 zie je veel in de praktijk. Hij lijkt op optie 1, maar dan wordt het type niet opgeslagen in de
Medewerker-tabel, maar in een aparte Medewerkerstype-tabel. Je legt dan met een vreemde sleutel een
verwijzing naar het desbetreffende type.

Bij optie 3 krijg je twee tabellen, een voor consultant en een voor accountmanager. Het nadeel hierbij zijn de
overeenkomstige attributen (zoals de “Werkt onder”-relatie), die moet je namelijk dubbel bijhouden. Optie 4
-12-
augustus 2016

lost dit op door wel een aparte medewerker-tabel te behouden. De onderliggende subtypes houden dan een
verwijzing bij naar de medewerker waar zij bij horen.

Tip: Teken de 4 verschillende vormen eens uit op papier om te zien hoe dit er uit ziet!

-13-
augustus 2016

4. Logische expressies
Wat is een logische expressie en waarom zou je deze nodig hebben? In de informatica ben je veelal met het
evalueren van condities bezig. Dat betekent gewoon dat je gegevens vergelijkt en afhankelijk van hun waarde
een beslissing neemt om het een of het ander te gaan doen: “Als x groter is dan 3 doe ik dit, anders iets
anders”.

Bij SQL kom je ook logische expressies tegen. Denk daarbij aan wat ingewikkeldere query’s en constraints
(volgende hoofdstukken). Om die op te lossen kan het helpen om ze eens goed te analyseren en als het waren
te ontleden. Zo houd je overzicht en maakt je minders snel fouten bij het opstellen van de query of constraint.

4.1 Een logisch voorbeeld


We beginnen met een eenvoudig voorbeeld. Stel je voor dat je gevraagd wordt om alle gebruikers uit de
database te moeten ophalen die ouder dan 18 zijn en als naam “Rik” of “Rick” hebben. Je komt met de
volgende oplossing (die helaas niet goed is).

SELECT * FROM Gebruiker


WHERE
leeftijd > 18 AND
naam = 'Rik' OR
naam = 'Rick';

Deze query gaat fout omdat het AND en de OR achterelkaar worden bekeken door het DBMS. Je krijgt nu een
overzicht van alle gebruikers die “Rick” heten of die “Rik” heten en ouder dan 18 zijn. Dat is niet helemaal wat
er gevraagd was. Het DBMS interpreteert de query eigenlijk als volgt.

SELECT * FROM Gebruiker


WHERE
(leeftijd > 18 AND
naam = 'Rik') OR
naam = 'Rick';

In dit soort gevallen doe je er dus goed aan om zelf haakjes te gebruiken in je query. Dan komt deze er als volgt
uit te zien.

SELECT * FROM Gebruiker


WHERE
leeftijd > 18 AND
(naam = 'Rik' OR
naam = 'Rick');

Bij grotere en meer ingewikkelde query’s en constraints is het vaak goed om haakjes te gebruiken. Dit
bevorderd de leesbaarheid en zorgt er voor dat je minder snel fouten maakt. Bovenstaand voorbeeld kunnen
we ook nog herschrijven tot een echt wiskundige logische expressie. Daarmee kunnen we eenvoudig de
correctheid nagaan.

4.2 Logische expressies


In de wiskunde schrijf je alles met letters zoals A, B en C om de abstraheren van de werkelijkheid. Zo kom je tot
de kern van het probleem en kun je dat eenvoudiger bevatten. We willen dat ook doen met het voorbeeld van
hierboven. We vervangen de individuele eisen die we aan een gebruikers stellen door letters. Dit mag
willekeurig, maar A, B en C zijn normale keuzes. Zie het volgende voorbeeld.
-14-
augustus 2016

leeftijd > 18 A
naam = 'Rik' B
naam = 'Rick' C

We kunnen nu zeggen dat we alle gebruikers willen hebben die voldoen aan A en aan óf B óf C. De logische
expressie wordt dan A AND (B OR C). Dit kun je met alles zo doen om ingewikkeld lijkende vergelijkingen te
herschrijven. Er is echter nog een soort stelling die we niet alleen maar met AND en OR kunt noteren.
Bijvoorbeeld de regel dat voor alle gebruikers jonger dan 12 jaar het wachtwoord langer dan 10 moet zijn.
Anders gezegd zou je kunnen stellen dat het wachtwoord langer dan 10 moet zijn wanneer een gebruiker
jonger is dan 12 jaar. Dus, uit het een volgt het ander.

leeftijd < 12 A
LENGTH(wachtwoord) > 10 B

De logische expressie is dan A ⇒ B. Dit spreek je uit als A impliceert B. Als je jonger bent dan 12 jaar, dan moet
de lengte van je wachtwoord groter zijn dan 10.

4.3 Expressies vereenvoudigen


Sommige expressies kun je nog verder vereenvoudigen, bijvoorbeeld in het voorbeeld van A ⇒ B van
hierboven. Voor SQL is dat in dit voorbeeld zelfs nodig aangezien er geen constructies zijn om de implicatie (de
pijl ⇒) te programmeren in SQL. De volgende twee expressies zijn logisch gezien equivalent (gelijk aan elkaar):

A⇒B
(NOT A) OR B

Het is maar wat je eenvoudiger noemt, maar zo kun je de implicatie herschrijven naar iets dat je wel kunt
programmeren in SQL. De NOT draait de stelling van A om. A stond voor leeftijd < 12. NOT A is dan leeftijd <=
12, waarbij het gelijkheidsteken belangrijk is!

We kunnen ook bewijzen dat de bovenstaande twee logische expressies gelijk aan elkaar zijn. Dat kun je
(onder andere) aantonen met behulp van waarheidstabellen.

4.4 Waarheidstabellen
Een waarheidstabel is een tabel waarin je kunt aflezen welke logische waardes (TRUE en FALSE) alle
parameters (A, B, C, enzovoorts) kunnen aannemen in een bepaalde expressie. Voor het gemak gebruiken we
1 voor TRUE en 0 voor FALSE. We nemen A AND (B OR C) weer als voorbeeld. We beginnen altijd door een
tabel van 1 parameter te maken, namelijk A, en daar alle logische waardes voor te noteren (TRUE en FALSE).

A
0
1

Dit is hopelijk nog goed te volgen. Deze tabel vertelt ons niet meer dan dat A twee verschillende waardes kan
aannemen, namelijk TRUE en FALSE. In de logische expressie staan ook de parameters B en C. Voor elke
nieuwe parameter die je toevoegt aan de waarheidstabel moet je de complete tabel kopiëren en eronder
plakken, als verdubbeling. Voeg nu de nieuwe parameter nu zodanig toe dat alle waarheidscombinaties met
voorgaande parameters in de tabel staan. Dat klinkt wat ingewikkeld, maar, een voorbeeld doet wonderen!
Wanneer we B toevoegen komt de waarheidstabel er als volgt uit te zien.

-15-
augustus 2016

A B
0 0
1 0
0 1
1 1

Zoals je kunt zien staan alle combinaties tussen A en B in de tabel. Zowel A als B zijn FALSE, of juist TRUE, een
van de twee is TRUE en de ander FALSE of andersom. Op dezelfde manier kun je C toevoegen, maar nu krijg je
eerst vier keer FALSE onder elkaar en daarna vier keer TRUE om unieke combinaties met A en B te maken.

A B C
0 0 0
1 0 0
0 1 0
1 1 0
0 0 1
1 0 1
0 1 1
1 1 1

Bovenstaande tabel is je beginpunt. Deze kun je direct maken zodra je de logische expressie ziet. Tel het aantal
parameters en maak de tabel op. Nu kun je een nieuwe kolom toevoegen, bijvoorbeeld B OR C, en deze
invullen aan de hand van de waardes van B en C.

A B C B OR C
0 0 0 0
1 0 0 0
0 1 0 1
1 1 0 1
0 0 1 1
1 0 1 1
0 1 1 1
1 1 1 1

Er komt dus alleen een 1 te staan in de rechter-kolom wanneer er in bij B of C een 1 staat. Nu kunnen we ook
de rest van de logische expressie toevoegen, namelijk A AND (B OR C).

A B C B OR C A AND (B OR C)
0 0 0 0 0
1 0 0 0 0
0 1 0 1 0
1 1 0 1 1
0 0 1 1 0
1 0 1 1 1
0 1 1 1 0
1 1 1 1 1

Deze tabellen kun je eenvoudig online laten genereren. Het is echter goed om te snappen hoe dit werkt. Het
versterkt namelijk je begrip en inzicht waardoor je eenvoudiger complexe query’s, constraints en andere
programmatuur zult kunnen programmeren.

Tip: Probeer de waarheidstabel voor (A AND B) OR C zelf te maken en merk de verschillen met bovenstaande.
-16-
augustus 2016

5. Constraints
Een constraint is vrij vertaald een beperking. Een beperking op de gegevens die je wilt opslaan in de database.
Deze constraints kun jij zelf aanmaken. Er zijn er een aantal die stuk voor stuk weer voor verschillende
toepassingen gebruikt kunnen worden en op andere manier geïmplementeerd moeten worden. In dit
hoofdstuk behandelen we de soorten constraints en bekijken we van een deel daarvan hoe je deze kunt
implementeren.

5.1 Uitleg
Zoals gezegd is een constraint een beperking die je als programmeur kunt aanmaken in de database. Meer
concreet, het is een regel of eis waar de informatie in een cel, rij, kolom, tabel of gehele database aan moet
voldoen. Bijvoorbeeld dat elke leeftijd in de leeftijd-kolom van de student-tabel groter moet zijn dan 17. Zodra
een nieuw gegeven niet voldoet aan alle constraints die van toepassing zijn zal deze niet worden opgeslagen.

De reden waarom deze regels nodig zijn is vanwege de consistentie van de informatie die wordt opgeslagen in
de database. Stel je voor dat inderdaad iedere student in jouw tabel minstens 18 moet zijn, maar dit heb je
niet met een constraint beschermd. Je kunt er dan voor kiezen om dit alsnog in je C#-programma te
controleren voordat je nieuwe gegevens in de student-tabel opslaat of wijzigt. Echter, iemand anders uit jouw
team maakt de mobile app voor jullie software. Hij vergeet deze constraint en controleert de leeftijd van de
studenten niet. Zodoende kunnen er alsnog foutieve gegevens worden opgeslagen. De vuistregel is “wat in de
database kan, doe je ook in de database”.

Vreemde en primaire sleutels zijn ook constraints. Stel je eens voor dat je deze niet zou gebruiken. Je kunt
zonder vreemde sleutels dan verwijzen naar gegevens die helemaal niet bestaan. Zonder primaire sleutels kun
je dubbele gegevens opslaan of deze zelfs leeg laten. Het DBMS controleert voor jou dat dit allemaal niet
gebeurd.

5.2 Soorten constraints


We definiëren vijf verschillende soorten constraints. Hieronder vind je een overzichtje.

Soort constraint Uitleg/voorbeeld


1 Attribuut Constraint op een attribuut (cell) in een tabel.
2 Tupel De constraint gaat over meerdere attributen in een tupel (rij/regel).
3 Tabel Regels in de tabel onderling hebben invloed op elkaar via de constraint.
4 Database De ene tabel legt beperkingen op andere tabellen via constraints.
5 Dynamisch Wordt geactiveerd bij veranderingen zoals toestandsovergangen.

De eerste twee typen constraints kunnen we prima in SQL programmeren. Voor de onderste drie hebben we
een krachtigere programmeertaal in de database nodig, zoals bijvoorbeeld T-SQL (zie later hoofdstuk).

Om je een beter beeld te geven van de verschillende soorten constraints gaan we ze allemaal langs met een
voorbeeld aan de hand van onderstaande tabellen.

Medewerker-tabel:
ID Naam Functie Salaris
7519 Bram Brentjens Project leider 4000
7520 Anna Althuis Requirements engineer 3400
7521 Karel Konings Kwaliteitsmanager 3000
7522 Piet Patter Secretaris 1800
7523 John Janssen Rapporteur 2000
-17-
augustus 2016

Requirement-tabel:
ID Beschrijving MoSCoW Medewerker_ID
2467 De gebruiker kan op… M 7520
2468 Wanneer op “verder”… M 7520
2469 Alleen een machinist… S 7519
2470 Zodra het systeem aan… W 7520

De Student_ID kolom uit de Requirement-tabel is een verwijzing (vreemde sleutel) naar de ID-kolom uit de
Medewerker-tabel.

5.2.1 Attribuut constraints


Attribuut constraints gaan over beperkingen of eisen op een veld in de database. Hieronder worden er twee
voorbeelden besproken.

Een voorbeeld van een attribuut constraint is de naam van een medewerker die verplicht ingevuld moet zijn.
Deze mag dus niet leeg worden gelaten. In het geval van de voorbeelden zijn alle velden ingevuld en wordt de
constraint dus niet overtreden.

Een ander voorbeeld is het salaris dat minstens €1900 moet zijn. Bij Piet Patter is dat niet het geval. Zijn salaris
zal eerst naar €1900 verhoogd moeten worden alvorens de constraint kan worden geïmplementeerd.

5.2.2 Tupel constraints


Een tupel constraint gaat over meerdere velden in een regel van een tabel in de database. Bijvoorbeeld dat het
salaris van een kwaliteitsmanager meer moet zijn dan €3100. Karel Konings is kwaliteitsmanager in ons
voorbeeld, maar verdient minder dan €3100. Zijn salaris zal dus verhoogd moeten worden naar meer dan
€3100 voordat de constraint geïmplementeerd kan worden.

Bij bovenstaande constraint is een implicatie nodig in de logische expressie. Stel je de volgende twee expressie
voor:

Functie = ‘kwaliteitsmanager’ A
Salaris > 3100 B

Dan krijg je A ⇒ B als logische expressie. Als de functie van iemand ‘kwaliteitsmanager’ is, moet gelden dat
salaris > 3100. Dit kun je zoals we eerder hebben gezien herschrijven naar de functie mag niet
‘kwaliteitsmanager’ zijn óf er moet gelden dat salaris > 3100. Ga dit zelf na als je dat nog niet hebt gedaan!

5.2.3 Tabel constraints


Wanneer je bepaalde eisen wilt stellen over meerdere rijen in een tabel heb je te maken met een tabel
constraint. Denk daarbij aan ons voorbeeld en wanneer we zouden willen garanderen in de database dat het
totaal aan salaris niet groter dan €12000 zou mogen zijn. In het voorbeeld is de inhoud van de Medewerker-
tabel dus in overtreding. De regel die als laatst is toegevoegd of gewijzigd waardoor het totaal boven de
€12000 uit is gekomen zou met de constraint niet doorgevoerd kunnen worden. Zo blijft je data altijd
consistent.

Dit soort zaken kun je niet met SQL programmeren (met uitzondering van de primaire en vreemde sleutels).
SQL kan namelijk alleen maar de gegevens van een bepaald veld of meerdere velden binnen een regel
evalueren. Zodra er informatie over meerdere regels of meerdere tabellen nodig is zal je een krachtigere taal
nodig hebben, zoals T-SQL.

-18-
augustus 2016

5.2.4 Database constraints


Zodra je gegevens uit meerdere tabellen moet vergelijken om een constraint te kunnen bewaken heb je het
over database constraints. Tot nu toe hebben we nog geen voorbeelden gezien met de Requirements-tabel.
Echter, wanneer we stellen dat alleen een requirements engineer gekoppeld mag zijn aan een daadwerkelijke
requirement, dan zal je toch echt twee tabellen moeten raadplegen. In dat geval moet je een database
constraint programmeren. Ook dat kan niet in SQL om dezelfde reden als bij tupel constraints. In het
voorbeeld voldoet requirement 2469 niet aan deze constraint omdat die door een project leider is toegevoegd
aan de tabel.

5.2.5 Dynamische constraints


De laatste categorie van constraints gaat over dynamische informatie. Denk daarbij aan bijvoorbeeld data die
veranderd wat alleen mag gebeuren onder bepaalde omstandigheden. Zo zou je kunnen stellen dat het salaris
alleen maar hoger zou mogen worden, niet lager. Helaas kan SQL niet de vorige waarde van een veld bekijken.
Ook daar is T-SQL voor nodig.

Ook kun je bepaalde functionaliteit programmeren die wordt gestart op het moment dat de database op
wordt gestart of juist af wordt gesloten. Dit soort complexe zaken zijn bij dit vak nog niet aan de orde, maar
deze kunnen logischerwijs ook niet in SQL worden geprogrammeerd.

5.3 Constraints in SQL


Gelukkig kunnen we een hoop constraints wel gewoon in SQL programmeren. In deze paragraaf zien we niet
hoe dat precies in SQL eruit ziet (dat gebeurt in een later hoofdstuk), maar maken wel alvast kennis met de
begrippen en termen.

De meest bekende constraints zijn de primaire en vreemde sleutel. Soms ook beter bekend als primairy key en
foreign key met als respectievelijke afkortingen PK en FK. Een primairy key is uniek en nooit leeggelaten. Aan
dat veld kun je elke regel in een tabel dus terugvinden. De FK is vaak gekoppeld aan een PK. Dit is een
verwijzing naar een ander veld in een andere tabel. Een regel verwijderen uit een tabel waar een andere regel
naar verwijst met een FK-constraint is dus ook niet mogelijk! We leren hier later nog wat trucjes voor.

Dan zijn er nog drie andere veel gebruikte constraints: nullable, unique en check. Je kunt een veld nullable
maken waarmee je aangeeft dat het veld eventueel leeggelaten mag worden. Denk daarbij aan een
telefoonnummer wat je bij registratie optioneel wel of niet kunt invullen. Een veld unique maken is precies
wat je verwacht, het is uniek. Denk daarbij aan je BSN of E-mailadres die beide altijd uniek moeten zijn binnen
een tabel. Met de check-constraint kun je wat ingewikkeldere zaken aangeven. Bijvoorbeeld dat het salaris
groter moet zijn dan een bepaalde waarde, dat het E-mailadres een @-symbool bevat of dat het huisnummer
is ingevuld wanneer de postcode is gegeven. De implementatie van deze constraints zien we in het hoofdstuk
over de Data Definition Language (DDL).

5.4 Constraints in het ontwerp


De PK, FK, nullable en unique constraints kunnen we allemaal
aangeven in het ontwerp. De check en meer ingewikkeldere
constraints die we later nog gaan zien kun je tekstueel geven bij het
databaseontwerp. Zo heeft de programmeur altijd een compleet
overzicht van alle constraints.

Hier rechts zie je een voorbeeld van een DBO van een Persoon-tabel
met constraints. Zoals je ziet is het ID van een persoon het
identificerende gegeven, de primaire sleutel (PK). Alle adressen
worden blijkbaar opgeslagen in een aparte tabel, want elk persoon heeft een verwijzing AdresID naar de PK
-19-
augustus 2016

van de Adres-tabel. Het E-mailadres van elk persoon moet uniek zijn. Je kunt je dus niet twee keer aanmelden
met hetzelfde E-mailadres in dit systeem. De geboortedatum mag leeggelaten worden want die is nullable (N)
en het gewicht niet.

Let op dat een veld ook meerdere constraints kan hebben. Zo kan het zijn dat de primaire sleutel een extra
check heeft. Een PK van een tabel kan ook een FK naar een andere tabel is. En een FK kan ook uniek zijn om 1-
op-1 relaties te programmeren. Let op dat de PK altijd al unique en not nullable is.

-20-
augustus 2016

6. DDL en DML
DDL staat voor Data Definition Language en DML voor Data Manipulation Language. Nu je weet hoe je een
ontwerp moet maken en constraints daarin kunt aangeven wordt het tijd om dat om te gaan zetten naar SQL.
Dat doe je met DDL. We gaan definiëren hoe de data wordt opgeslagen (CREATE). Daarna gaan we die
informatie manipuleren door er gegevens aan toe te voegen (INSERT), te wijzigen (UPDATE), verwijderen
(DELETE) en in te zien (SELECT).

Het is allemaal geen hogere wiskunde en het is voornamelijk een hoop zelf uitzoeken, uitproberen en gewoon
doen. We beginnen met het aanmaken van de tabellen en constraints.

6.1 Een tabel aanmaken


Wanneer we het voorbeeld nemen van de Persoon-tabel uit het vorige hoofdstuk dan kun je dat aanmaken in
de database met het volgende stukje SQL.

CREATE TABLE Persoon (


ID INT PRIMARY KEY,
AdresID INT NOT NULL REFERENCES Adres(ID),
EmailAdres NVARCHAR(75) NOT NULL UNIQUE,
Geboortedatum DATE,
Gewicht DOUBLE(5,2) NOT NULL
);

Het begint dus met CREATE TABLE en dan de naam de persoon gevuld door alle kolommen tussen haakjes,
gescheiden door komma’s. Voor elke kolom geef je de naam van die kolom aan, het type en eventueel de
constraints indien mogelijk. In tegenstelling tot het ontwerp is in SQL elke kolom standaard nullable en moet je
expliciet aangeven wanneer deze niet leeg gelaten mag worden door er NOT NULL bij te zetten. Dat is het
tegenovergestelde van wat we bij het databaseontwerp hebben gezien.

Het is ook mogelijk om na de laatste kolom nog extra constraints toe te voegen. Dat kan handig zijn omdat je
de constraints dan ook een naam kunt geven. De naam van een constraint is handig wanneer je deze moet
verwijderen of wanneer de constraint juist voor problemen zorgt. Het DBMS zal dan de naam van de
constraint gebruiken om je duidelijk te maken dat er iets mee aan de hand is. Bijvoorbeeld zoals in het
volgende voorbeeld.

CREATE TABLE Medewerker (


ID INT PRIMARY KEY,
Naam INT NOT NULL CHECK LEN(Naam) > 1,
Functie NVARCHAR(75),
Salaris DOUBLE(5,2) NOT NULL,

CONSTRAINT ck_MinSalaris Salaris >= 1900


);

-21-
augustus 2016

In het in SQL uitgewerkte voorbeeld van de Medewerker-tabel kun je twee check-constraints zien. De lengte
van de naam van een Medewerker moet minstens 2 lang zijn en het minimale salaris moet €1900 zijn. De
lengte van de naam wordt gecontroleerd met een in-kolom constraint. Het minimale salaris wordt
gecontroleerd met een in-tabel constraint. Deze constraint heeft als naam ck_MinSalaris.

6.2 Een tabel aanpassen


Wanneer je een tabel eenmaal hebt aangemaakt staat deze in de database. Vanaf dat moment kan er
informatie aan toegevoegd worden. Wanneer er iets aan de structuur van de tabel gewijzigd moet worden,
dan zal je dat expliciet aan moeten geven aan het DBMS middels de juiste SQL-commando’s (ALTER). Denk
daarbij aan het wijzigen van de naam van de tabel, het toevoegen of verwijderen van kolommen en constraints
en eigenlijk alles wat je maar kunt verzinnen.

In onderstaand voorbeeld zie je hoe je een kolom kunt toevoegen aan een tabel.

ALTER TABLE Persoon


ADD Voornaam NVARCHAR(32) NOT NULL;

In het volgende voorbeeld kun je zien hoe je een constraint toevoegt aan een tabel.

ALTER TABLE Persoon


ADD CONSTRAINT ckEmailCorrect
CHECK EmailAdres LIKE '%@%';

Op soortgelijke manier kun je ook kolommen en constraints verwijderen.

6.3 Een tabel verwijderen


Het verwijderen van een tabel is zeer eenvoudig. Let er wel op dat er geen andere tabellen zijn die nog naar de
tabel verwijzen. Anders zal de FK-constraint daar over gaan klagen.

DROP TABLE Persoon;


DROP TABLE Medewerker;

-- Dit gaat mis vanwege de bestaande verwijzing vanuit Medewerker!

DROP TABLE Requirement;


DROP TABLE Medewerker;

-- In de goede volgorde gaat het wel goed.

-22-
augustus 2016

Zorg er dus altijd voor dat je eerst tabellen verwijderd waar geen andere tabellen naar verwijzen. Daarna de
andere. Je kunt ook eerst zelf de constraint verwijderen volgens het volgende voorbeeld. Let er dan wel op dat
je de FK dan toevoegt met een zelf ingegeven naam.

ALTER TABLE Requirement


DROP FOREIGN KEY fk_MedewerkerID;

6.4 Data manipulatie


Met DML kun je gegevens toevoegen, wijzigen, verwijderen en selecteren uit tabellen. Het selecteren van
gegevens uit een tabel hebben we al gezien en wordt ook in een volgend hoofdstuk nog behandeld. Hieronder
zie je drie voorbeelden.

INSERT INTO Persoon VALUES (10, 32, 'voorbeeld@live.com', NULL, 70);


UPDATE Persoon SET Gewicht = 80 WHERE ID = 10;
DELETE FROM Persoon WHERE ID = 10;

Let er op dat het verwijderen van gegevens uit een tabel zonder de WHERE-clausule resulteert in een lege
tabel zonder gegevens. Dit kun je niet meer terugdraaien.

6.5 Transacties
Het is geen onderdeel van DDL of DML, maar bij deze wordt het kort benoemd. Als je met de database bezig
bent kun je bepaalde acties clusteren en als geheel doorvoeren naar het DBMS en daarmee permanent maken
of terugdraaien sinds het begin van de transactie. Zie het volgende korte voorbeeld.

BEGIN TRANSACTION t_Voorbeeld;

<DML-statements>

COMMIT TRANSACTION t_Voorbeeld;

Op het moment dat de transactie wordt doorgevoerd met een COMMIT staan alle gegevens in de database.
Mocht er tussentijds iets niet helemaal gaan zoals je had voorspeld, dan kun je deze nog terugdraaien met het
volgende commando.

BEGIN TRANSACTION t_Voorbeeld;

<DML-statements>

-23-
augustus 2016

ROLLBACK TRANSACTION t_Voorbeeld;

Alle DML-statements zullen nu teruggedraaid worden. Let er op dat DDL-statements impliciet ook een
COMMIT uitvoeren. Wanneer je tussen je DML dus een DDL-commando uitvoert wordt als het voorgaande dus
doorgevoerd. Bij een ROLLBACK zal alles voor het DDL-commando dus blijven staan in de database. Dat kun je
niet meer terugdraaien!

-24-
augustus 2016

7. Geavanceerde SQL
Het selecteren van informatie uit een database doe je middels SQL, wat op zichzelf weer een onderdeel is van
de Data Manipulation Language zoals we hebben kunnen lezen. Als het goed is heb je al enige ervaring met
SQL. We beginnen dit hoofdstuk met een korte herhaling en duiken daarna dieper in de materie. Denk daarbij
aan meer ingewikkelde JOIN-constructies zoals de OUTER en recursieve JOIN.

7.1 Gegevens selecteren


Elke SQL query bestaat verplicht uit een SELECT en een FROM-onderdeel. Daarna heb je nog optioneel een
WHERE, GROUP BY en een ORDER BY. Eventueel kun je bij het gebruik van een GROUP BY binnen een groep
een HAVING-clausule toevoegen om de samenstelling van de groep aan te passen (te filteren) in het resultaat
van je query.

Je kunt bij de SELECT verschillende gegevens aangeven die je zou willen selecteren. Gebruik een asterisk-
symbool (*) om alle beschikbare kolommen uit de tabellen die je in de FROM hebt gespecificeerd te
selecteren. Anders kun je separate kolommen aangeven uit de tabellen, gescheiden door komma’s.

In de FROM zet je alle tabellen die je nodig hebt om alles te selecteren. Let er op dat je ze koppelt door middel
van een JOIN met de PK en FK. Wanneer je dat eenmaal hebt gedaan kun je in de SELECT alle kolommen
gebruiken uit alle tabellen die in de FROM staan. Let er op dat je aangeeft uit welke tabel je de gegevens wilt
hebben voor die kolommen die dezelfde naam hebben in verschillende tabellen. Je kunt tabellen ook een alias
geven door na de naam van de tabel een nieuwe naam op te geven. Vaak is dit de eerste letter van de tabel.
Voor een Student-tabel zou je dus S nemen. Zie het volgende voorbeeld.

SELECT S.StudentNummer, R.Cijfer


FROM Student S JOIN Resultaat R ON S.ID = R.StudentID
WHERE S.leeftijd < 18
ORDER BY S.StudentNummer ASC;

Hierboven zie je een voorbeeld van de meest voorkomende JOIN. Dit is de INNER JOIN. We kijken verderop
waarom deze zo wordt genoemd en wat voor een varianten je nog meer hebt. We koppelen de cijfers aan de
studenten. Daarbij moeten we wel de juist cijfers aan de juiste studenten koppelen. Vandaar dat we de twee
tabellen moeten koppelen met de JOIN.

Met de WHERE-clausule kunnen we een soort filter aangeven. In bovenstaand voorbeeld geven we aan alleen
maar de resultaten van die studenten te willen zien die jonger dan 18 jaar oud zijn. De ORDER BY zorgt er voor
dat alle resultaten worden gesorteerd op oplopend (ASC) studentnummer. Zet er DESC in plaats van ASC
achter om de sortering te laten aflopen.

7.2 Rekenen en groeperen


In de SELECT-clausule kun je ook rekenen. Je kunt bijvoorbeeld het volgende uitvoeren.

SELECT
Prijs AS PrijsExBTW,
Prijs * 1.21 AS PrijsInBTW
-25-
augustus 2016

FROM Product;

In het voorbeeld zie je dat je dus zelf kolommen kunt aanmaken door allerlei gegevens te combineren en er
optioneel mee te rekenen. In dit geval nemen we de prijs van een product inclusief en exclusief BTW. In de
database wordt alleen maar de exclusief-prijs opgeslagen. De prijs inclusief BTW moeten we dus nog
uitrekenen. Dat kan zoals aangegeven in de SELECT-clausule.

Je kunt ook ingebouwde SQL-functies gebruiken zoals de COUNT, SUM, MIN, MAX en AVG. Hiermee kun je
respectievelijk het aantal, de som, het minimum, het maximum en het gemiddelde van een bepaalde set
opvragen. Zo krijg je door SELECT COUNT(*) FROM Gebruiker uit te voeren het aantal gebruikers
terug. SELECT SUM(Prijs) FROM Bestelling geeft de optelling van alle prijzen van alle bestellingen.
Om de gemiddelde prijs van een product op te vragen kun je SELECT AVG(Prijs) FROM Product
uitvoeren.

Let er op dat je moet groeperen zodra je naast een functie ook andere kolommen wilt gebruiken. De vuistregel
is dat je alle kolommen die je naast de functie(s) in de query gebruikt ook in de GROUP BY moet zetten. Bekijk
onderstaand voorbeeld.

SELECT COUNT(*), leeftijd


FROM Student
GROUP BY leeftijd;

Wanneer je bovenstaande query zou uitvoeren kan je, afhankelijk wat voor database je gebruikt, een
foutmelding verwachten. Je vraagt namelijk het totaal aantal studenten op (dat is 1 waarde) en alle leeftijden
van de studenten (dat zijn waarschijnlijk meerdere waardes). Zodra je op leeftijd groepeert zal het DBMS het
aantal studenten per groep gaan tellen. Bovenstaande query geeft dus een overzicht van het aantal studenten
per leeftijd. Let daar goed op!

7.3 Tabellen samenvoegen


Voor de volgende twee onderwerpen, de INNER en OUTER JOIN, maken we gebruik van het volgende
voorbeeld.

Student-tabel:
ID Naam Geboortedatum SLB_ID

7519 Bram Brentjens 24-01-1998 1215


7520 Anna Althuis 02-06-1996 1215
7521 Karel Konings 31-05-1996 1216

7522 Piet Patter 28-11-1997 1216

7523 John Janssen 14-08-1998 1216

Docent-tabel:

-26-
augustus 2016

ID Naam Geboortedatum Salarisschaal

1215 Willem Wasven 24-01-1979 12

1216 Vicci Vlas 02-06-1975 12

1217 Xander Xavier 31-05-1981 13

Bij elke student is bijgehouden wie hij of zij als SLB heeft. Het SLB_ID in de student-tabel verwijst naar het ID
van een docent. Zoals je kunt zien heeft Xander Xavier geen studenten waar hij SLB van is.

7.3.1 INNER JOIN


Het samenvoegen van resultaten die uit meerdere tabellen afkomstig zijn doen we in SQL met de JOIN. Tot
voorkort hebben we dat altijd gedaan met de INNER JOIN. Echter, er zijn bepaalde vragen die je niet zo
eenvoudig met een INNER JOIN kunt beantwoorden. Stel je voor dat je twee tabellen hebt met studenten en
met docenten. Je kunt met een INNER JOIN de namen van alle studenten met diens SLB opvragen met
bijvoorbeeld de volgende query.

SELECT S.Naam, D.Naam AS SLB


FROM
Student S INNER JOIN
Docent D ON S.SLB_ID = D.ID;

Bij elke student wordt via de vreemde sleutel het ID


van de docent gezocht die SLB is van die specifieke
student. Zo voorkom je dat de verkeerde docent bij
een student wordt gevonden.

Schematisch zou je de INNER JOIN je als volgt kunnen Docent Student


voorstellen zoals in het plaatje hier rechts. Alle
docenten zitten in de linker cirkel, en rechts zitten alle
studenten. De docenten die gekoppeld zijn aan een
student als SLB zitten in de overlap in het midden. Dit
zijn dus alle studenten waarvoor het SLB_ID is ingevuld
en refereert naar een bepaalde docent. Je krijgt dan
het volgende resultaat.

Naam SLB

Bram Brentjens Willem Wasven


Anna Althuis Willem Wasven
Karel Konings Vicci Vlas
Piet Patter Vicci Vlas
John Janssen Vicci Vlas

-27-
augustus 2016

Het wordt echter complexer wanneer je de namen van alle docenten moet opvragen met, indien aanwezig, de
namen van al zijn of haar SLB-studenten. Dat is het witte gedeelte van de linker docent-cirkel, inclusief de
overlap met student. In dat geval zal de INNER JOIN die docent niet aan een student kunnen koppelen. Die zijn
er namelijk niet. In dat geval zal de betreffende docent niet in het resultaat worden meegenomen. In het
voorbeeld zou Xander Xavier bijvoorbeeld niet in het resultaat voorkomen omdat hij geen studenten naar hem
refereren. Hij is geen SLB. Om dit netjes op te lossen heb je een andere JOIN nodig. Dat is de OUTER JOIN.

7.3.2 OUTER JOIN


Wanneer je alles gegevens uit de ene tabel wilt koppelen
aan een andere tabel, maar ook wanneer die koppeling
niet gemaakt kan worden vanwege een ontbrekende
vreemde sleutel, dan heb je een OUTER JOIN nodig. Docent Student
Schematisch ziet dat er uit zoals in het plaatje hier
rechts.

Stel je wilt een overzicht van alle docenten en diens SLB-


studenten. Dus ook de docenten die geen SLB zijn. Dan
krijg je de volgende query.

SELECT S.Naam, D.Naam AS SLB


FROM
Docent D LEFT OUTER JOIN
Student S ON S.SLB_ID = D.ID;

Zoals je kunt zien in bovenstaande query wordt hier een LEFT OUTER JOIN toegepast. Onthoud het als “de
linker kant” is primair in deze query. Dus de student-tabel die links van de LEFT JOIN staat is de tabel waar je
alle gegevens van wilt.

Er is ook zo iets als een RIGHT OUTER JOIN, wat eigenlijk hetzelfde is als de linkse variant. Wanneer je de twee
tabellen in de FROM-clausule omdraait kun je van de LEFT een RIGHT maken en heb je dezelfde query. Dit ziet
er dan als volgt uit.

SELECT S.Naam, D.Naam AS SLB


FROM
Student S RIGHT OUTER JOIN
Docent D ON S.SLB_ID = D.ID;

Een OUTER JOIN is dus link- of rechtsom altijd hetzelfde, mits je de tabellen maar aan de juiste kant zet. Het
resultaat ziet er dan als volgt uit.

-28-
augustus 2016

ID Naam Geboortedatum Salarisschaal Student

1215 Willem Wasven 24-01-1979 12 Bram Brentjens


1215 Willem Wasven 24-01-1979 12 Anna Althuis
1216 Vicci Vlas 02-06-1975 12 Karel Konings
1216 Vicci Vlas 02-06-1975 12 Piet Patter
1216 Vicci Vlas 02-06-1975 12 John Janssen
1217 Xander Xavier 31-05-1981 13

De student bij Xander Xavier blijft leeg (NULL).

7.3.3 FULL OUTER JOIN


Dan heb je tot slot nog een FULL OUTER JOIN. Daarmee krijg je
in het voorbeeld alle docenten en alle studenten die aan elkaar
gekoppeld kunnen worden, maar ook die niet gekoppeld kunnen
worden. Dus je krijg alle SLB-docenten met diens studenten, alle
docenten die geen SLB zijn en alle studenten die om wat voor Docent Student
reden nog geen SLB hebben. Schematisch krijg je dan het figuur
hier rechts.

Het bijbehorende SQL-commando voor de FULL OUTER JOIN


voor ons voorbeeld zie je hieronder.

SELECT S.Naam, D.Naam AS SLB


FROM
Student S FULL OUTER JOIN
Docent D ON S.SLB_ID = D.ID;

In de praktijk zal je deze variant niet zo snel tegenkomen.

7.4 Recursieve JOIN


We zijn bij het modelleren en ontwerpen ook recursieve relaties tegengekomen. Hier kan zijn dat je daar een
query moet verzinnen die een dergelijke relatie nodig heeft om de gegevens op te vragen die nodig zijn. In zo’n
geval heb je te maken met een recursieve JOIN. Dit kan een INNER of OUTER JOIN zijn. Het gaat er bij
recursieve JOIN om dat je een tabel koppelt aan dezelfde tabel. Vaak wordt deze JOIN de SELF of AUTO JOIN
genoemd.

Bekijk het volgende voorbeeld.

-29-
augustus 2016

Een medewerkers-tabel:
ID Naam Functie Salaris MangerdByID

2721 Antonie Aarts Programmeur 2500 2725


2722 Bart Blasvink UX designer 2800 2725
2723 Caroline Caspers Software architect 3500 2725
2724 Dirk Dolfsen Programmeur 2600 2725
2725 Erna Edings Manager 4700 2726
2726 Frits Fazant CEO 10000

In bovenstaand voorbeeld kun je zien dat elke medewerker een manager boven zich kan hebben. Iedereen is
een medewerker en iedereen, behalve de CEO Frits Fazant, heeft een manager die zelf ook weer een
medewerker is. De medewerker-tabel heeft dus een recursieve-relatie. Via het ManagedByID kom je uit bij de
manager van de desbetreffende medewerker.

We willen de namen van alle medewerkers opvragen inclusief de naam van diens manager. Voor deze query
zullen we de recursieve relatie moeten gebruiken. Via het ManagedByID moeten we bij de manager uitkomen.
We hebben dus twee keer de medewerker-tabel nodig. Een keer voor de naam van de medewerker zelf en nog
een keer voor de naam van de manager. We komen dan uit op de volgende query.

SELECT med.Naam, man.Naam AS Manager


FROM
Medewerker med LEFT JOIN
Medewerker man ON man.ID = med.ManagedByID;

Omdat je twee keer dezelfde tabel gebruik in de FROM-clausule, is het van belang om deze een alias te geven.
Met die alias kun je in de SELECT-clausule aangeven uit welke van de twee tabellen je de gegevens wilt
selecteren. Wanneer je dit niet doet zal SQL je een foutmelding geven. Welke naam wil je dan selecteren, die
van de medewerker of van de manager?

7.5 Gecorreleerde subquery


Tot slot behandelen we in deze laatste paragraaf de gecorreleerde subquery. Eenvoudig gezegd is een
subquery een SELECT-statement in een andere query. Een gecorreleerde subquery is een speciaal soort
subquery waarin je binnen die subquery ook een link legt naar de hoofd-query. Laten we weer een voorbeeld
bekijken. We gebruiken daar dezelfde medewerker-tabel voor als in de vorige paragraaf over de recursieve
JOIN.

Stel we willen weten welke medewerkers er allemaal meer verdienen dan het gemiddelde van alle
medewerkers onder dezelfde manager. De toevoeging op het eind van de vorige zin over het gemiddelde
salaris van alle medewerkers die onder dezelfde manager vallen is moeilijk. Dat lijkt een beetje op een groep,
maar is juist de correlatie. De oplossing zit ‘m in het feit dat je dit probleem in twee delen moet oplossen en
later moet samenvoegen.

Als eerste wordt een overzicht gevraagd van alle medewerkers die meer verdienen dan een bepaald
gemiddelde. Laten we even €3000 kiezen als gemiddeld salaris. Dan ziet de query er als volgt uit.
-30-
augustus 2016

SELECT M.ID, M.Naam


FROM Medewerker M
WHERE M.Salaris > 3000;

In het tweede gedeelte van de query wil je het gemiddelde salaris van alle medewerkers weten die onder een
en dezelfde manager vallen. Stel, we pakken voor nu even de manager met ID 2725. Dat is medewerker Erna
Edings. De query die we zoeken ziet er als volgt uit.

SELECT AVG(med.Salaris)
FROM Medewerker med
WHERE med.ManagedByID = 2725;

In de query hierboven selecteren we het gemiddelde salaris van alle medewerkers die als manager de
medewerker met ID 2725 hebben.

Nu moeten we de twee query’s combineren. Het gemiddelde salaris van alle medewerkers onder dezelfde
manager is niet €3000. Dat gemiddelde hebben we uitgezocht met de tweede query. Die kunnen we dus als
sub-query gebruiken. Dat levert ons het volgende tussenresultaat op.

SELECT M.ID, M.Naam


FROM Medewerker M
WHERE M.Salaris > (
SELECT AVG(med.Salaris)
FROM Medewerker med
WHERE med.ManagedByID = 2725
);

Echter, het manger ID dat we zoeken is ook niet 2725. Dat moet hetzelfde ID zijn als van de manager uit de
hoofd-query. Dus die moeten we aan elkaar gelijk stellen. Dat maakt de query gecorreleerd. De hoofd-query
houdt verband met de sub-query. We komen dan tot onderstaand resultaat.

SELECT M.ID, M.Naam


FROM Medewerker M
WHERE M.Salaris > (
SELECT AVG(med.Salaris)
FROM Medewerker med
WHERE med.ManagedByID = M.ManagedByID
);

-31-
augustus 2016

8. T-SQL
Zoals al een paar keer eerder in dit dictaat aan bod is gekomen zijn er niet voor alle problemen een passende
oplossing in SQL. Daar heb je bepaalde technieken voor nodig die meer mogelijkheden bieden dan SQL. Een
voorbeeld daarvan is Microsoft’s T-SQL dat staat voor Transact-SQL. In dit hoofdstuk vind je de basis over dit
onderwerp om er zelf verder mee aan de slag te kunnen.
8.1 Uitleg
T-SQL is een Microsoft uitbreiding op SQL. Andere bekende uitbreidingen met vergelijkbare functionaliteit zijn
stored procedures van MySQL en PL/SQL van Oracle. De basis die je al gewend ben uit C# heeft waarschijnlijk
wel een soortgelijke oplossing in T-SQL. Denk daarbij aan variabelen, if-statements, loops en methodes. Ook
kun je er bijvoorbeeld exceptions en file I/O mee programmeren.

SQL is een declaratieve taal. Dat wil zeggen dat je als programmeur met SQL kunt zeggen welke gegevens je
wilt hebben. Het is niet mogelijk om het DBMS te vertellen hoe hij dat moet doen. C# en ook T-SQL zijn
imperatieve programmeertalen. Daarmee kun je zeggen hoe bepaalde bewerkingen uitgevoerd dienen te
worden. Beide hebben hun voor- en nadelen.

SQL is heel goed in het kort en krachtig noteren van welke gegevens er opgehaald moeten worden of wat voor
een object er in een database aangemaakt moet worden. Je kunt er echter geen tussentijdse gegevens mee
onthouden om ze op een later tijdstip in je code of script te hergebruiken. Ook kun je de volgorde van een
bewerking niet aangeven. Dit is waar je een imperatieve programmeertaal als T-SQL voor nodig hebt.

T-SQL zorgt voor performance winst ten opzichte van C# omdat de code in de database is opgeslagen.
Daarmee kan T-SQL dus sneller door alle gegevens zoeken en gemakkelijker SQL uitvoeren. Je kunt grote
problemen opdelen in kleinere deelproblemen en dus modulair maken. Net zoals je dat in C# doet eigenlijk.
Dat vergroot de leesbaarheid van je code. Ook zijn bepaalde delen dan herbruikbaar voor andere
programmeurs en andere projecten. Daarmee boek je tijdwinst en hoe je de code niet telkens opnieuw te
programmeren. Ook kun je er met T-SQL voor zorgen dat bepaalde database-gerelateerde programmatuur is
afgeschermd van andere programmeurs die geen toegang tot de database hebben. Daarmee voorkom je dat
anderen de gegevens in de database kunnen ver…
8.2 Procedures en functies
Net als in C# en andere programmeertalen kun je in T-SQL variabelen maken, if-statements gebruiken, loops
toepassen, maar ook methodes aanmaken en gebruiken. Er zijn twee soorten methodes, namelijk procedures
en functies. Een procedure is een methode zonder return-value. Een functie geeft wel een waarde terug als
resultaat. Verder is er geen verschil tussen de twee.

Bekijk het volgende voorbeeld in T-SQL.

CREATE PROCEDURE HaalWerknemerOp(


@Achternaam nvarchar(50),
@Voornaam nvarchar(50)
) AS
SELECT
Voornaam, Achternaam,
Functie, Afdeling
FROM Werknemer

-32-
augustus 2016

WHERE Voornaam = @Voornaam AND


Achternaam = @Achternaam;
GO

Deze procedure haalt alle medewerkers op met een bepaalde voor- en achternaam. De naam van de
procedure is HaalWerknemerOp en heeft twee parameters, Achternaam en Voornaam, beide aangegeven met
het @-symbool. Na AS komt de body van de procedure. Wanneer het sleutelwoord GO wordt gegeven zal het
voorgaande T-SQL object naar de DBMS worden gepersisteerd.

Het volgende voorbeeld maakt gebruik van een return-waarde. Dit is dus een functie.

CREATE FUNCTION HaalInventarisOp(@ProductID int)


RETURNS int
AS
-- Haalt de voorraad van een product op.
BEGIN
DECLARE @ret int;
SELECT @ret = SUM(p.Aantal)
FROM ProductInventaris p
WHERE p.ProductID = @ProductID;
IF (@ret IS NULL)
SET @ret = 0;
RETURN @ret;
END;
GO

Deze functie geeft een integer terug als resultaat. Op de eerste regel van de function body (na de BEGIN)
wordt een lokale variabele ret aangemaakt van het type int. De SUM van alle producten wordt opgehaald met
een SQL statement. Er wordt daarna nog een extra check gedaan voordat deze waarde wordt geretourneerd.

8.3 Triggers
Om complexe constraints te kunnen maken in de database heb je veelal triggers nodig. Een trigger is een
methode die wordt uitgevoerd op het moment dat een bepaald event in de database optreedt. Je kunt het
vergelijken met een event handler.

Je kunt bij een trigger aangeven dat deze bijvoorbeeld wordt uitgevoerd na een INSERT, UPDATE of DELETE
statement. Hij kan vervolgens de methode één keer uitvoeren of per regel uit het INSERT, UPDATE of DELETE
statement. Bekijk de volgende voorbeelden.

CREATE TRIGGER tr_Orders_INSERT


ON Orders FOR INSERT
AS
IF EXISTS (SELECT * FROM inserted WHERE Prioriteit = 'Hoog')
-33-
augustus 2016

BEGIN
DECLARE @Count int;
SET @Count = (SELECT COUNT(*) FROM inserted
WHERE Prioriteit = 'Hoog');
PRINT CAST(@Count AS varchar(3)) + ' regel(s) met hoge prioriteit.';
END;
GO

Bovenstaande trigger laat het aantal orders met hoge prioriteit zien die zijn toegevoegd aan de orders-tabel.
De inserted-tabel, net als de deleted tabel, is een bijzondere in-memory tabel die SQL Server aanmaakt bij
triggers. Alle regels die bij het INSERT-statement worden toegevoegd aan de tabel waar de trigger op staat
komen tijdelijk in die tabel. Iets soortgelijks gebeurt bij het verwijderen met de deleted-tabel. Voor UPDATE-
statements worden de regels die aangepast gaan worden eerst in de deleted-tabel gezet en daarna in de
inserted-tabel.

CREATE TRIGGER trg_InsteadOf_INSERT ON Persoon


INSTEAD OF INSERT
AS
BEGIN
IF (NOT EXISTS (SELECT P.Naam
FROM Persoon P, inserted I
WHERE P.Naam = I.Naam))
INSERT INTO Person SELECT Naam FROM inserted;
END;
GO

De trigger uit bovenstaand voorbeeld is een zogenaamde instead of trigger. Die wordt uitgevoerd voorafgaand
aan de uitvoering van het INSERT, UPDATE en/of DELETE statement. De trigger vervangt het INSERT, UPDATE
en/of DELETE statement dat eigenlijk uitgevoerd zou worden. Je moet deze dus nog expliciet toevoegen aan de
trigger wanneer je het statement alsnog wilt uitvoeren. Dat gebeurt ook in het voorbeeld hierboven.

Deze instead-of trigger wordt dus uitgevoerd voordat de INSERT statements daadwerkelijk in de database
staan. Zo kun je controleren of er bijvoorbeeld al een persoon met dezelfde naam bestaat. Dit kan uiteraard
veel beter met een UNIQUE constraint, maar het laat goed de opbouw en het nut van de instead-of trigger
zien, want je kunt hier veel complexere controles mee uitvoeren natuurlijk.

8.4 Cursors
Elke uitkomst van een SQL-query komt in een apart stuk geheugen te staan van het DBMS. Een cursor is een
soort verwijzing naar dat stukje geheugen. Het kan namelijk soms nuttig zijn om regel voor regel door het
resultaat van een query te lopen. Cursors gebruik je veelal in combinatie met een loop. Denk daarbij aan een
foreach-loop waar je per regel iets uit een filestream haalt. Elke regel die je binnenhaalt bestaat weer uit losse
onderdelen. Denk aan de velden (kolommen) in een tabel.

Bekijk het volgende voorbeeld.

-34-
augustus 2016

CREATE PROCEDURE PrintMedewerkers AS


DECLARE @MedewerkerNaam AS NVARCHAR(50);
DECLARE @MedewerkerCursor AS CURSOR;
SET @MedewerkerCursor = CURSOR FOR
SELECT * FROM Werknemer;
OPEN @MedewerkerCursor;
FETCH NEXT FROM @MedewerkerCursor INTO @MedewerkerNaam;
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT 'Medewerker: ' + @MedewerkerNaam;
FETCH NEXT FROM @MedewerkerCursor INTO @MedewerkerNaam;
END;
CLOSE @MedewerkerCursor;
DEALLOCATE @MedewerkerCursor;
GO

Deze methode loopt door alle mederwerkers en print stuk voor stuk alle namen. Uiteraard kun je vele
ingewikkeldere zaken uitvoeren per loop-iteratie, maar het toont kort en krachtig het gebruik en de toepassing
van een cursor.

-35-

You might also like