Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1of 18

Uitwerkingen opdrachten werkboek hoofdstuk 10

Opgave 1b

Van sommige boeken zijn meerdere exemplaren aanwezig. Voor de bibliotheek is het
belangrijk te weten welk exemplaar van elk boek aan welke leerling is uitgeleend. Vandaar de
kolom EXNR in uitleningen. De tabel Reserveringen heeft deze kolom niet, want als een
leerling een boek wil reserveren dan doet hij of zij dat uitsluitend op titel.

Opgave 1c

De kolom BOEKNR staat in de tabel Reserveringen. Als je wilt weten welk boek daarbij
hoort kun je dat aan de hand van de kolom BOEKNR in de tabel Boeken opzoeken.
De kolom AUTEURNR staat in de tabel Boeken. Als je wilt weten welke schrijver daarbij
hoort kun je dat aan de hand van de kolom AUTEURNR in de tabel Auteurs opzoeken.

Opgave 2a

SELECT VOORNAAM, TUSSENVOEGSEL, ACHTERNAAM, KLAS


FROM LEERLINGEN
ORDER BY KLAS, ACHTERNAAM

Opgave 2b

SELECT VOORNAAM, TUSSENVOEGSEL, ACHTERNAAM, GEB_JAAR


FROM AUTEURS
ORDER BY GEB_JAAR, ACHTERNAAM

Opgave 2c

SELECT TITEL, RUBRIEK


FROM BOEKEN
ORDER BY RUBRIEK, TITEL

Opgave 3a

SELECT DISTINCT BOEKNR


FROM UITLENINGEN
ORDER BY BOEKNR

Opgave 3b

SELECT DISTINCT KLAS


FROM LEERLINGEN

Opgave 4a

SELECT VOORNAAM, TUSSENVOEGSEL, ACHTERNAAM


FROM LEERLINGEN
WHERE ACHTERNAAM = 'Dijkstra'
Opgave 4b

SELECT VOORNAAM, TUSSENVOEGSEL, ACHTERNAAM


FROM AUTEURS
WHERE GEB_JAAR > 1900

Opgave 4c

SELECT TITEL, RUBRIEK


FROM BOEKEN
WHERE RUBRIEK <> 'Nederlands'

Opgave 4d Eerst een query maken om het auteurnummer van de schrijver te vinden.
Probleem is dat je niet precies weet hoe de schrijver heet. Gebruik dus LIKE.

SELECT VOORNAAM, TUSSENVOEGSEL, ACHTERNAAM, AUTEURNR


FROM AUTEURS
WHERE ACHTERNAAM LIKE 'Reve'

Het auteurnummer blijkt 62 te zijn. Nu de boeken vinden.

SELECT TITEL
FROM BOEKEN
WHERE AUTEURNR = 62

Opgave 4e

SELECT VOORNAAM, TUSSENVOEGSEL, ACHTERNAAM, AUTEURNR


FROM AUTEURS
WHERE ACHTERNAAM= 'Maugham'

Het auteurnummer blijkt 92 te zijn. Nu de boeken vinden.

SELECT TITEL
FROM BOEKEN
WHERE AUTEURNR = 92

Er blijken inderdaad twee boeken van deze schrijver in de bibliotheek te zijn.

Opgave 5a

SELECT VOORNAAM, TUSSENVOEGSEL, ACHTERNAAM


FROM LEERLINGEN
WHERE ACHTERNAAM LIKE 'Frederi*'
Opgave 5b

SELECT VOORNAAM, TUSSENVOEGSEL, ACHTERNAAM


FROM LEERLINGEN
WHERE VOORNAAM LIKE '*an*'

Opgave 5c

SELECT TITEL
FROM BOEKEN
WHERE TITEL LIKE '*vos*'

Opgave 6a

SELECT VOORNAAM, TUSSENVOEGSEL, ACHTERNAAM, STRAAT, PLAATS,


KLAS
FROM LEERLINGEN
WHERE KLAS = '4b'
AND STRAAT = 'Julianaweg'
AND PLAATS = 'Utrecht'

Opmerking: deze query levert geen resultaat op: blijkbaar wonen er geen leerlingen in de
Julianaweg. Je kunt het controleren door de volgende regel weg te laten:

AND STRAAT = 'Julianaweg'

Opgave 6b

SELECT VOORNAAM, TUSSENVOEGSEL, ACHTERNAAM, KLAS,


GEB_DATUM
FROM LEERLINGEN
WHERE KLAS LIKE '6?'
AND GEB_DATUM > #01-jan-1985#

Opgave 6c

SELECT VOORNAAM, TUSSENVOEGSEL, ACHTERNAAM, PLAATS


FROM LEERLINGEN
WHERE PLAATS = 'Bunnik'
OR PLAATS = 'Schalkwijk'

Opgave 7b

De laatste eis PLAATS = 'Bunnik' staat los van de eis KLAS = '5b' waardoor de leerlingen
uit Bunnik ook in andere klassen kunnen zitten.
Opgave 7c

SELECT *
FROM LEERLINGEN
WHERE (
KLAS = '5b' AND PLAATS = 'Utrecht'
)

OR PLAATS = 'Bunnik'

Opgave 7d

SELECT *
FROM LEERLINGEN
WHERE KLAS = '5b'
AND (
PLAATS = 'Utrecht' OR PLAATS = 'Bunnik'
)

Opgave 7e

AND en OR gedragen zich als * en + in een berekening.


Vermenigvuldigingen en AND gaan voor optellen en OR.
Met extra haakjes kun je er voor zorgen dat een optelling of een OR toch voorgaat.

Met getallen gaat het zo:

7 * 5 + 2 = 35 + 2 = 37

7 * (5 + 2) = 7 * 7 = 49

Met logische expressies gaat het zo:

KLAS LIKE ’5*’ AND GESLACHT= ‘v’ OR KLAS=’5a’

Dit zijn alle leerlingen die voldoen aan de voorwaarde (KLAS LIKE ’5*’ AND
GESLACHT= ‘v’) óf (OR KLAS=’5a’).

Mét haakjes kun je de betekenis veranderen:

KLAS LIKE ’5*’ AND (GESLACHT= ‘v’ OR KLAS=’5a’)

Nu moet het een leerling uit een 5e klas zijn EN een meisje uit 5a (begrijp je dat het eerste
deel nu overbodig geworden is? In het tweede deel moet het immers per se klas 5a zijn)
Opgave 8a

SELECT VOORNAAM, TUSSENVOEGSEL, ACHTERNAAM, POSTCODE


FROM LEERLINGEN
WHERE POSTCODE LIKE '352??B'
OR POSTCODE LIKE '352??R'
OR POSTCODE LIKE '352??P'

Opgave 9b

Eerst een query maken om te kijken hoe oud Jantine de Bakker nu eigenlijk precies is:

SELECT VOORNAAM, TUSSENVOEGSEL, ACHTERNAAM, POSTCODE,


GEB_DATUM
FROM LEERLINGEN
WHERE VOORNAAM = 'Jantine'
AND TUSSENVOEGSEL = 'de'
AND ACHTERNAAM = 'Bakker'

Resultaat: zij is geboren op 28 juli 1986.

De eerste eis is dat de jongen ouder is dan haar, maar ook weer niet te oud, een jaar ouder is in
orde.

SELECT VOORNAAM, TUSSENVOEGSEL, ACHTERNAAM, TELEFOON,


GESLACHT, GEB_DATUM
FROM LEERLINGEN
WHERE GESLACHT = 'm'
AND GEB_DATUM >= #28-jul-1985#
AND GEB_DATUM < #28-jul-1986#

De twee eis is wat soepeler: nu mag de jongen nog wel twee jaar ouder zijn, maar dan moet
hij bij haar in de buurt wonen. Haar postcode volgt uit de eerste query en is 3523 HZ.
De query wordt nu:

SELECT VOORNAAM, TUSSENVOEGSEL, ACHTERNAAM, TELEFOON,


GESLACHT, GEB_DATUM
FROM LEERLINGEN
WHERE GESLACHT = 'm'
AND GEB_DATUM >= #28-jul-1985#
AND GEB_DATUM < #28-jul-1986#
OR (
GESLACHT = 'm'
AND GEB_DATUM > #28-jul-1984#
AND GEB_DATUM < #28-jul-1986#
AND POSTCODE LIKE '3523??'
)

Opvallend is dat de tweede eis, dus het gedeelte na de OR, geen extra namen oplevert!
Let op: in openoffice moet je een andere datumnotatie gebruiken (zie de tip op de website)

Opgave 9a

SELECT MAX(BOETE)
FROM UITLENINGEN

Opgave 9b

SELECT AVG(BOETE)
FROM UITLENINGEN

Opgave 9c

Voor de oudste leerling:

SELECT MIN(GEB_DATUM)
FROM LEERLINGEN

Voor de jongste leerling:

SELECT MAX(GEB_DATUM)
FROM LEERLINGEN

Opgave 9d

SELECT COUNT(*)
FROM EXEMPLAREN
WHERE STATUS = 'in reparatie'

Opgave 10a

SELECT PLAATS, COUNT(*)


FROM LEERLINGEN
GROUP BY PLAATS

Opgave 10b

SELECT GESLACHT, COUNT(*)


FROM LEERLINGEN
GROUP BY GESLACHT

Opgave 10c

SELECT KLAS, GESLACHT, COUNT(*)


FROM LEERLINGEN
GROUP BY KLAS, GESLACHT

Opgave 10d
SELECT RUBRIEK, COUNT(*)
FROM BOEKEN
GROUP BY RUBRIEK

Opgave 11a

SELECT VOORNAAM, TUSSENVOEGSEL, ACHTERNAAM, GEB_DATUM


FROM LEERLINGEN
WHERE GEB_DATUM =
(
SELECT MIN(GEB_DATUM)
FROM LEERLINGEN
)

Voor de oudste leerling gebruik je dezelfde query en vervang je MIN door MAX.

Je kunt beide resultaten ook in één keer krijgen met:

SELECT *
FROM LEERLINGEN
WHERE GEB_DATUM =
(
SELECT MIN(GEB_DATUM)
FROM LEERLINGEN
)
OR GEB_DATUM =
(
SELECT MAX(GEB_DATUM)
FROM LEERLINGEN
)

Opgave 11b

‘WHERE GEB_DATUM =’ is beter, omdat je zeker weet dat er maar één minimale
geboortedatum bestaat.

Opgave 11c

SELECT TITEL
FROM BOEKEN
WHERE RUBRIEK = 'Nederlands'
AND BOEKNR IN
(
SELECT BOEKNR
FROM EXEMPLAREN
WHERE STATUS = 'in reparatie'
)

Opgave 11d

SELECT VOORNAAM, TUSSENVOEGSEL, ACHTERNAAM


FROM AUTEURS
WHERE AUTEURNR IN
(
SELECT AUTEURNR
FROM BOEKEN
WHERE BOEKNR IN
(
SELECT BOEKNR
FROM RESERVERINGEN
)
)

Opgave 11e

SELECT VOORNAAM, TUSSENVOEGSEL, ACHTERNAAM


FROM LEERLINGEN
WHERE LLNR IN
(
SELECT LLNR
FROM UITLENINGEN
WHERE BOEKNR =
(
SELECT BOEKNR
FROM BOEKEN
WHERE TITEL = 'Hoe vreselijk is dit alles'
AND DATUM_TERUG IS NULL
)
)

Dit geeft overigens een lege tabel...

Opgave 12a

SELECT VOORNAAM, TUSSENVOEGSEL, ACHTERNAAM, TITEL


FROM AUTEURS, BOEKEN
WHERE AUTEURS.AUTEURNR = BOEKEN.AUTEURNR

Opgave 12b

SELECT VOORNAAM, TUSSENVOEGSEL, ACHTERNAAM, BOETE


FROM LEERLINGEN, UITLENINGEN
WHERE LEERLINGEN.LLNR = UITLENINGEN.LLNR
AND BOETE > 0
Opgave 12c

SELECT VOORNAAM, TUSSENVOEGSEL, ACHTERNAAM, TITEL,


STERF_JAAR
FROM AUTEURS, BOEKEN
WHERE AUTEURS.AUTEURNR = BOEKEN.AUTEURNR
AND PUB_JAAR < 1900
AND PUB_JAAR >= 1800

Als je ook zeker wilt weten dat er exemplaren zijn moet je ook de tabel exemplaren gebruiken

SELECT VOORNAAM, TUSSENVOEGSEL, ACHTERNAAM, TITEL,


STERF_JAAR
FROM AUTEURS, BOEKEN, EXEMPLAREN
WHERE AUTEURS.AUTEURNR = BOEKEN.AUTEURNR
and BOEKEN.BOEKNR=EXEMPLAREN.BOEKNR
AND PUB_JAAR < 1900
AND PUB_JAAR >= 1800

‘In de bibliotheek’ leggen we niet uit als ‘niet uitgeleend’

Opgave 12d

SELECT VOORNAAM, TUSSENVOEGSEL, ACHTERNAAM


FROM AUTEURS, BOEKEN, EXEMPLAREN
WHERE AUTEURS.AUTEURNR = BOEKEN.AUTEURNR
AND BOEKEN.BOEKNR = EXEMPLAREN.BOEKNR
AND STATUS = 'in reparatie'

Opgave 12e

Als je wilt weten welke boeken aan leerlingen uit 6V uitgeleend zijn kan dat vrij eenvoudig.

SELECT *
FROM BOEKEN
WHERE RUBRIEK=’NEDERLANDS’
AND BOEKNR IN

(
SELECT BOEKNR
FROM UITLENINGEN
WHERE LLNR IN

(
SELECT LLNR
FROM LEERLINGEN
WHERE KLAS LIKE ‘6?’
)
)

Als je echter de gegevens van de leerlingen en de auteurs ook in het antwoord wilt hebben,
wordt het een ingewikkelde koppeling tussen 4 tabellen:

SELECT L.ACHTERNAAM, A.ACHTERNAAM, B.TITEL


FROM LEERLINGEN L, AUTEURS A,BOEKEN B, UITLENINGEN U
WHERE L.LLNR=U.LLNR AND A.AUTEURNR=B.AUTEURNR AND
B.BOEKNR=U.BOEKNR AND L.KLAS LIKE '6?' AND
B.RUBRIEK='NEDERLANDS'

Opgave 13a

SELECT PLAATS, COUNT(*)


FROM LEERLINGEN
GROUP BY PLAATS
HAVING COUNT(*)>10

opgave 13b

SELECT *
FROM AUTEURS
WHERE AUTEURNR IN

(
SELECT AUTEURNR
FROM BOEKEN
GROUP BY AUTEURNR
HAVING COUNT(*)>5
)

opgave 13c

SELECT *
FROM BOEKEN
WHERE BOEKNR IN
(
SELECT BOEKNR
FROM UITLENING
GROUP BY BOEKNR
HAVING COUNT(*)>10
)

opgave 14a

SELECT *
FROM BOEKEN
WHERE NOT EXISTS
(
SELECT *
FROM UITLENINGEN
WHERE BOEKEN.BOEKNR=UITLENINGEN.BOEKNR
)

Het kan ook zonder exists:

SELECT *
FROM BOEKEN
WHERE NOT (LLNR IN
(
SELECT LLNR
FROM UITLENINGEN
WHERE BOEKEN.BOEKNR=UITLENINGEN.BOEKNR
)
)

Je maakt er dus een query van de volgende vorm van:

NOT (<veldnaam> IN <subquery>).

opgave 14b

SELECT *
FROM LEERLINGEN
WHERE NOT EXISTS
(
SELECT LLNR
FROM UITLENINGEN AS U, BOEKEN AS B
WHERE RUBRIEK=’NEDERLANDS’
AND U.BOEKNR=B.BOEKNR
)

Je kunt deze query ook zonder exists schrijven:

SELECT *
FROM LEERLINGEN
WHERE NOT (LLNR IN
(
SELECT LLNR
FROM UITLENINGEN AS U, BOEKEN AS B
WHERE RUBRIEK=’NEDERLANDS’
AND U.BOEKNR=B.BOEKNR
)
)
opgave 15, maken we niet als views, maar gewoon als query

OPGAVE 15A
SELECT L.*,B
FROM LEERLINGEN AS L,
(
SELECT U.LLNR, SUM(U.BOETE) AS B
FROM UITLENINGEN AS U
GROUP BY U.LLNR
) AS S
WHERE L.LLNR=S.LLNR

opgave 15b

Let op: er wordt nu in de FROM een subquery gebruikt

SELECT L.*,B
FROM LEERLINGEN AS L,
(
SELECT U.LLNR, SUM(U.BOETE) AS B
FROM UITLENINGEN AS U
GROUP BY U.LLNR
HAVING SUM(U.BOETE)>5
) AS S
WHERE L.LLNR=S.LLNR

opgave 15c

in reparatie

SELECT *
FROM BOEKEN
WHERE BOEKNR IN
(
SELECT BOEKNR
FROM EXEMPLAREN
WHERE STATUS='IN REPARATIE'
)

Vervang ‘in reparatie’ door ‘thuis’ en ‘uitgeleend’ voor de twee andere vragen
Je kunt ze ook ale drie in de where schrijven met een OR ertussen:

WHERE (STATUS='IN REPARATIE')


OR (STATUS='IN REPARATIE' )
OR (STATUS='IN REPARATIE' )
opgave 16

overslaan

opgave 17

(ga er vanuit dat het vandaag 3 maart 2006 is)

opgave 17a

SELECT TITEL, LEERLINGEN.VOORNAAM, LEERLINGEN.TUSSENVOEGSEL,


LEERLINGEN.ACHTERNAAM, AUTEURS.VOORNAAM,
AUTEURS.TUSSENVOEGSEL, AUTEURS.ACHTERNAAM, DATUM_UIT
FROM AUTEURS, BOEKEN, LEERLINGEN, UITLENINGEN
WHERE AUTEURS.AUTEURNR = BOEKEN.AUTEURNR
AND BOEKEN.BOEKNR = UITLENINGEN.BOEKNR
AND LEERLINGEN.LLNR = UITLENINGEN.LLNR
AND DATUM_UIT < #3-MAR-2006# AND DATUM_TERUG IS NULL;

Let op: in openoffice moet je een andere datumnotatie gebruiken (zie de tip op de website)

Opgave 17b,c overslaan

opgave 18

SELECT EXNR
FROM EXEMPLAREN
WHERE BOEKNR=

(
SELECT BOEKNR
FROM BOEKEN
WHERE TITEL = "GIPH!"
)
AND STATUS = "THUIS";

opgave 19

We zoeken naar reserveringen die beschikbaar zijn sinds 21 februari of eerder, waarbij geen
uitlening hoort van na de 'datum_beschikbaar'. Dit laatste vinden met behulp van een
subquery met NOT EXISTS.
Helemaal nodig is deze subquery niet. Als een gereserveerd boek wordt opgehaald, moet de
status veranderd worden in 'opgehaald', en is de status van de reservering niet meer
'beschikbaar', maar een query zoals deze is toch wel aardig!
Als de query reserveringen vindt, volgt er een update in de database (reservering wordt
'vervallen') en een fysieke actie van de bibliothecaris (boek wordt teruggezet in de kast met
uitleenbare boeken). De verandering van status zorgt er ook voor dat een reservering niet twee
keer vervalt.
SELECT *
FROM RESERVERINGEN AS R
WHERE STATUS = "beschikbaar"
AND NOT EXISTS
(
SELECT *
FROM UITLENINGEN AS U
WHERE U.LLNR=R.LLNR
AND U.BOEKNR=R.BOEKNR
AND U.DATUM_UIT >= R.DATUM_BESCHIKBAAR
)
AND R.DATUM_BESCHIKBAAR <= #21-feb-2002#

Zonder subquery

SELECT A.ACHTERNAAM, B.TITEL, L.ACHTERNAAM


FROM AUTEURS AS A, BOEKEN AS B, LEERLINGEN AS L,
RESERVERINGEN AS R
WHERE A.AUTEURNR = B.AUTEURNR
AND B.BOEKNR=R.BOEKNR
AND L.LLNR=R.LLNR
AND R.DATUM_BESCHIKBAAR = {D '2006-02-21'}
AND R.STATUS= 'BESCHIKBAAR'

opgave 20a
SELECT TITEL
FROM BOEKEN, UITLENINGEN
WHERE BOEKEN.BOEKNR = UITLENINGEN.BOEKNR
AND DATUM_UIT < #10-FEB-2006#
AND DATUM_TERUG IS NULL;

Let op: in openoffice moet je een andere datumnotatie gebruiken (zie de tip op de website)

opgave 20b
Voor boeknr 66 gaat het als volgt.

SELECT VOORNAAM, TUSSENVOEGSEL, ACHTERNAAM


FROM LEERLINGEN
WHERE LLNR IN
(
SELECT LLNR
FROM RESERVERINGEN
WHERE BOEKNR=66
AND DATUM_RESERVERING <=#3-MAR-2006#
AND STATUS = "OPEN"
);

Let op: in openoffice moet je een andere datumnotatie gebruiken (zie de tip op de website)
Maar dat is niet goed genoeg!

Voor de aanmaningen moeten we drie weken terug naar 8 februari. Verder bevat de query
alleen veel joins om de gewenste gegevens op te halen.
Punt is overigens wel dat we aan de data niet kunnen zien of een uitlening al eerder is
aangemaand, er is geen status-variabele.

SELECT L.VOORNAAM, L.TUSSENVOEGSEL, L.ACHTERNAAM, L.KLAS,


U.DATUM_UIT, A.VOORLETTERS, A.TUSSENVOEGSEL, A.ACHTERNAAM,
B.TITEL
FROM LEERLINGEN AS L, UITLENINGEN AS U, EXEMPLAREN AS E,
BOEKEN AS B, AUTEURS AS A
WHERE L.LLNR = U.LLNR
AND U.BOEKNR = E.BOEKNR
AND U.EXNR = E.EXNR
AND E.BOEKNR = B.BOEKNR
AND B.AUTEURNR = A.AUTEURNR
AND DATUM_UIT < #8-feb-2002#
AND DATUM_TERUG IS NULL

opgave 21

Opgave 22a
Een query met groeperen:

SELECT B.TITEL, A.ACHTERNAAM, COUNT(*) AS AANTAL


FROM AUTEURS AS A, BOEKEN AS B, EXEMPLAREN AS E
WHERE A.AUTEURNR= B.AUTEURNR
AND B.BOEKNR = E.BOEKNR
AND E.UITLEENBAAR='J'
GROUP BY B.TITEL, A.ACHTERNAAM, B.BOEKNR

Als je meer gegevens van de auteur in de select wilt weergeven, moet e die wel ook in de
GROUP BY zetten.

SELECT B.BOEKNR, B.TITEL, A.VOORLETTERS, A.TUSSENVOEGSEL,


A.ACHTERNAAM, COUNT(*) AS AANTAL_EX
FROM EXEMPLAREN AS E, BOEKEN AS B, AUTEURS AS A
WHERE E.BOEKNR = B.BOEKNR
AND B.AUTEURNR = A.AUTEURNR
AND UITLEENBAAR = "j"
GROUP BY B.BOEKNR, B.TITEL, A.VOORLETTERS, A.TUSSENVOEGSEL,
A.ACHTERNAAM

opgave 22b
SELECT B.TITEL, A.ACHTERNAAM, COUNT(*)
FROM BOEKEN AS B, AUTEURS AS A, UITLENINGEN AS U
WHERE B.BOEKNR = U.BOEKNR
AND B.AUTEURNR=A.AUTEURNR
AND U.DATUM_UIT > {D '2004-09-01'}
GROUP BY B.BOEKNR, B.TITEL, A.ACHTERNAAM

Het toevoegen van de tabel exemplaren mag, maar is niet nodig.


En er kunnen natuurlijk ook meer gegevens in de SELECT staan (maar dan ook in de GROUP
BY)

SELECT B.BOEKNR, B.TITEL, A.VOORLETTERS, A.TUSSENVOEGSEL,


A.ACHTERNAAM, COUNT(*) AS AANTAL_UITL
FROM EXEMPLAREN AS E, BOEKEN AS B, AUTEURS AS A, UITLENINGEN
AS U
WHERE E.BOEKNR = B.BOEKNR
AND B.AUTEURNR = A.AUTEURNR
AND U.BOEKNR = E.BOEKNR
AND U.EXNR = E.EXNR
AND U.DATUM_UIT > #1-sep-2001#
GROUP BY B.BOEKNR, B.TITEL, A.VOORLETTERS, A.TUSSENVOEGSEL,
A.ACHTERNAAM

Het mooist is 't natuurlijk om de query's te combineren en een rangschikking te maken van het
aantal uitleningen per exemplaar. Dit is makkelijk, omdat we de twee afzonderlijke query's al
hebben. Die heb je dan bijvoorbeeld bewaard onder de twee namen, die je bij FROM ziet
staan:

SELECT AE.*, AU.AANTAL_UITL, AANTAL_UITL/AANTAL_EX AS


UITL_PER_EX
FROM [Query23a AantalExPerBoek] AS AE, [Query23b AantalUitlPerBoek] AS AU
WHERE AE.BOEKNR=AU.BOEKNR
ORDER BY AANTAL_UITL/AANTAL_EX DESC

Query's als deze leiden tot vragen over query's die bijvoorbeeld een top-10 opleveren. Deze
zijn zeer ingewikkeld en daarom uit het boek van deel 2 weggelaten. Hier nog wel de uitleg
over hoe je deze query's zou kunnen maken.

Bij het genereren van tabellen die antwoord geven op vragen rond 'de 10 hoogste' of 'de
twintig kleinste' zou je kunnen denken aan iets van de vorm:

SELECT *
FROM <tabel>
ORDER BY <kolom waarvan je de top-10 wil zien>
HAVING RANK < 10

Regels zoals de laatste zijn alleen niet gedefinieerd in SQL. De gewenste tabel moet daarom
via een omweg geproduceerd worden.
Als voorbeeld bekijken we de cijfertabel 'CIJFER2', de tabel met drie kolommen uit hoofdstuk
12, opdracht 6. De vraag is: Geef de tien hoogste examenresultaten.
We beginnen met het maken van een join van deze tabel met zichzelf. Omdat we nu alle
namen dubbel hebben, moeten we AS gebruiken (niet behandeld in het boek) om de twee
kopieën te onderscheiden. Als voorwaarde stellen we dat het cijfer in de tweede kopie groter
of gelijk moet zijn aan het cijfer in de eerste kopie.

SELECT HOOFD.*, BIJ.*


FROM CIJFERS2 AS HOOFD, CIJFERS2 AS BIJ
WHERE BIJ.CIJFER>=HOOFD.CIJFER
ORDER BY HOOFD.CIJFER

We krijgen nu een (lange) tabel met zes kolommen. De drie kolommen links zijn afkomstig
uit de kopie die we HOOFD genoemd hebben. In de kolom HOOFD.CIJFER zal het hoogste
cijfer maar één keer voorkomen (aangenomen dat alle examenresultaten verschillend zijn, het
verhaal wordt wat ingewikkelder, maar in principe niet anders als er dubbelen voorkomen).
De voorwaarde is dat het cijfer in de kopie BIJ groter of gelijk moet zijn. Alleen het hoogste
cijfer zelf voldoet aan deze voorwaarde. De rij met het hoogste cijfer komt in HOOFD dus
maar één keer voor, gekoppeld aan zichzelf.
Het op één na hoogste cijfer komt twee keer voor, gekoppeld aan zichzelf en aan de rij met het
hoogste resultaat. Nummer drie komt drie keer voor, enzovoorts.
Door te groeperen op de gegevens in HOOFD en te tellen hoe vaak de rijen voorkomen,
krijgen we rangnummers:

SELECT HOOFD.LLNR, HOOFD.VAK, HOOFD.CIJFER, COUNT(*)


FROM CIJFERS2 AS HOOFD, CIJFERS2 AS BIJ
WHERE BIJ.CIJFER>=HOOFD.CIJFER
GROUP BY HOOFD.LLNR, HOOFD.VAK, HOOFD.CIJFER
ORDER BY COUNT(*)

Wanneer de cijfers allemaal verschillen, krijgen we een tabel met de resultaten in volgorde,
met de rangnummers (uit de COUNT) 1, 2, 3, enzovoorts erbij. Met een HAVING selecteren
we de top-10: HAVING COUNT(*)<=10' bij het groeperen.
Wanneer er wel gelijken zijn, komen de ex-aequo-noteringen er ook uit, maar dan met het
laagste rangnummer: De cijfertabel geeft twee negens (elk met rangnummer 2), twee 8.9's (elk
met rangnummer 4) twee 8.7's (rang 6) en zes 8.6'en (rang 12). De HAVING geeft daarom
slechts een top-6!
Het probleem van de hoogste totale boetes kan worden opgelost door van de query uit het
begin een view te maken en daarop eenzelfde query als voor de cijfers los te laten.
HOOFDSTUK 10

Opgave 3a
INSERT INTO uitleningen(llnr, exnr, boeknr, datum_uit)
VALUES('83','1','13','2006-03-03')

Opgave 3b
UPDATE leerlingen
SET STRAAT = 'Veldwachterserf', HUISNUMMER = 14, PLAATS = 'Houten', POSTCODE
= '3991KW'
WHERE llnr = 77

Opgave 3c
DELETE FROM reserveringen
WHERE llnr = 78

Opgave 4
CREATE TABLE leden
(
llnr INT NOT NULL AUTO_INCREMENT,
voornaam VARCHAR(15) NOT NULL,
tussenvoegsel VARCHAR(10),
achternaam VARCHAR(20) NOT NULL,
straat VARCHAR(20) NOT NULL,
huisnummer INT NOT NULL,
postcode VARCHAR(6) NOT NULL,
plaats VARCHAR(20) NOT NULL,
telefoon VARCHAR(10),
geslacht VARCHAR(1) NOT NULL,
geb_datum DATE NOT NULL,
klas VARCHAR(2),
PRIMARY KEY(llnr)
);

CREATE TABLE reserveringen


(
boeknr INT NOT NULL,
llnr INT NOT NULL,
datum_reservering DATE,
datum_beschikbaar DATE,
kosten_betaald VARCHAR(1) NOT NULL,
PRIMARY KEY(boeknr, llnr, datum_reservering)
)

You might also like