Database SQL

advertisement
2010
ROC ter AA T&T Team ICT
Cees Loomans
[DATABASE SQL]
Een aanzet tot de standaard vraagtaal SQL.
Database SQL
1 mei 2010
Inhoud
Inleiding SQL .................................................................................................................................. 5
Het opzetten van de database (DDL) ............................................................................................. 6
De CREATE TABLE opdracht ....................................................................................................... 6
De ALTER TABLE opdracht ......................................................................................................... 7
De DROP TABLE opdracht .......................................................................................................... 8
Integriteitbewaking met de UNIQUE INDEX .............................................................................. 9
Indexeren ................................................................................................................................... 9
VRAGEN EN OPDRACHTEN .................................................................................................. 11
VRAGEN ............................................................................................................................... 11
OPDRACHTEN ...................................................................................................................... 11
Het werken met Gegevens (DML) ............................................................................................... 12
Het vullen van de tabel met behulp van INSERT ..................................................................... 12
VRAGEN EN OPDRACHTEN .................................................................................................. 14
VRAGEN ............................................................................................................................... 14
OPDRACHTEN ...................................................................................................................... 14
Fundamentele opdrachten met SELECT ...................................................................................... 15
VRAGEN ............................................................................................................................... 20
OPDRACHTEN ...................................................................................................................... 20
DISTINCT .................................................................................................................................. 21
OPDRACHTEN ...................................................................................................................... 22
Rekenen met kolominhouden ................................................................................................. 23
OPDRACHTEN ...................................................................................................................... 24
Operatoren in het WHERE gedeelte. ....................................................................................... 25
OPDRACHTEN ...................................................................................................................... 26
Het combineren van operatoren met AND en OR................................................................... 27
In SQL kunnen we dan gebruik maken van AND en OR....................................................... 27
OPDRACHTEN ...................................................................................................................... 28
VRAGEN EN OPDRACHTEN .................................................................................................. 30
VRAGEN ............................................................................................................................... 30
OPDRACHTEN ...................................................................................................................... 30
BETWEEN ................................................................................................................................. 31
OPDRACHTEN ...................................................................................................................... 31
IN.............................................................................................................................................. 32
OPDRACHTEN ...................................................................................................................... 32
Hoofdstuk: Inleiding SQL
Het gebruik van NOT................................................................................................................ 29
2
Database SQL
1 mei 2010
LIKE .......................................................................................................................................... 33
OPDRACHTEN ...................................................................................................................... 33
NULL......................................................................................................................................... 34
OPDRACHTEN ...................................................................................................................... 34
ORDER BY ................................................................................................................................. 35
OPDRACHTEN ...................................................................................................................... 36
GROUP BY, HAVING, COUNT, AVG, SUM, MAX en MIN .......................................................... 37
Count ................................................................................................................................... 38
AVG ...................................................................................................................................... 38
SUM ..................................................................................................................................... 38
MAX en MIN......................................................................................................................... 39
HAVING ................................................................................................................................ 40
OPDRACHTEN ...................................................................................................................... 41
HET RAADPLEGEN VAN MEERDERE TABELLEN ............................................................................ 42
De verschillende mogelijkheden ............................................................................................. 42
De JOIN .................................................................................................................................... 44
OPDRACHTEN ...................................................................................................................... 46
De OUTERJOIN ......................................................................................................................... 47
De AUTOJOIN ........................................................................................................................... 47
OPDRACHTEN ...................................................................................................................... 49
De NON-EQUIJOIN ................................................................................................................... 50
De SUBQUERY .......................................................................................................................... 50
OPDRACHTEN ...................................................................................................................... 52
ANY en ALL ............................................................................................................................. 53
OPDRACHTEN ...................................................................................................................... 53
De gesynchroniseerde SUBQUERY .......................................................................................... 55
De EXISTS operator .............................................................................................................. 56
OPDRACHTEN ...................................................................................................................... 56
OPDRACHTEN ...................................................................................................................... 58
VEEL VOORKOMENDE PROBLEMEN MET DE SELECT OPDRACHT ............................................... 59
De denkwijze............................................................................................................................ 59
Nog nooit ... ............................................................................................................................. 59
OPDRACHTEN ...................................................................................................................... 60
Alleen maar ... .......................................................................................................................... 60
OPDRACHTEN ...................................................................................................................... 61
Hoofdstuk: Inleiding SQL
UNION, MINUS en INTERSECT ................................................................................................. 57
3
Database SQL
1 mei 2010
De (dubbele) ontkenning ......................................................................................................... 62
OPDRACHTEN ...................................................................................................................... 63
Alle ... ....................................................................................................................................... 64
OPDRACHTEN ...................................................................................................................... 66
DE DATA DICTIONARY .................................................................................................................. 67
Het principe van de data dictionary ........................................................................................ 67
De data dictionary als bewaker van de database. ................................................................... 67
VIEWS........................................................................................................................................... 70
Het principe van de VIEW ........................................................................................................ 70
Het maken van een VIEW ........................................................................................................ 70
OPDRACHTEN ...................................................................................................................... 72
Het verwijderen van een VIEW ................................................................................................ 72
GEGEVENS WIJZIGEN ................................................................................................................... 73
De verschillende mogelijkheden ............................................................................................. 73
INSERT .................................................................................................................................. 73
OPDRACHTEN ...................................................................................................................... 73
UPDATE ................................................................................................................................ 74
OPDRACHTEN ...................................................................................................................... 74
DELETE ................................................................................................................................. 75
OPDRACHTEN ...................................................................................................................... 75
GEGEVENS BEVEILIGEN................................................................................................................ 76
Vormen van gegevensbeveiliging ............................................................................................ 76
Bescherming tegen verlies................................................................................................... 76
Autorisatie van gebruik........................................................................................................ 76
VRAGEN ............................................................................................................................... 79
Hoofdstuk: Inleiding SQL
OPDRACHTEN ...................................................................................................................... 79
4
Database SQL
1 mei 2010
Inleiding SQL
De bedoeling van de cursus is om te leren SQL vragen te stellen aan een relationele database.
Door het zelfstandig doornemen van de cursus en daarbij de vragen en opdrachten te maken
leert de student hoe hij of zij een database kan bevragen. We maken daarbij gebruik van de
database MYSQL en een voorbeeld database.
Vraag aan je docent hoe je de database benaderd.
SQL (in Amerikaanse termen uit te spreken als 'sequel') is sedert de eerste publicaties van
Codd in 1971 en Boyce en Chamberlin in 1973 in sneltempo uitgegroeid tot de standaardtaal
voor vierde generatie relationele databases.
Juist omdat SQL zo nauw aansluit bij de reeds bekende relationele algebra en calculus en vrij
eenvoudige instructies kent voor alle aspecten van het opzetten en beheren van een database
is de populariteit van SQL snel toegenomen en nog steeds groeiende.
Een waarschuwing is hierbij meteen van belang: SQL is inderdaad vrij snel aan te leren en lijkt
daardoor de oplossing voor vele problemen.
Niets is minder waar. In het nu volgende zal ik proberen om aan de hand van een voorbeeld
database duidelijk te maken hoe eenvoudig SQL aan te leren is. Aan de andere kant hoop ik
ook duidelijk te maken dat deze eenvoud meteen het grootste gevaar is omdat men al snel
denkt de juiste oplossing gevonden te hebben, terwijl achteraf soms blijkt dat dit nu juist niet
het geval was!
Hoofdstuk: Inleiding SQL
SQL wordt veel gebruikt in combinatie met dynamisch gegenereerde webpagina’s op het
internet. Hierbij worden allerlei gegevens, artikelen en dergelijke in de database opgeslagen en
indien nodig opgeroepen en getoond. Om later zelf dynamische pagina’s te kunnen maken is
kennis van SQL noodzakelijk.
5
Database SQL
1 mei 2010
Het opzetten van de database (DDL)
De CREATE TABLE opdracht
Voor het opzetten van tabellen kent SQL een vrij eenvoudig commando namelijk het CREATE
TABLE commando dat er als volgt uit ziet:
CREATE TABLE <tabelnaam>
(
<kolomnaam> <kolomtype> {(<lengte>)} {NOT NULL},
<kolomnaam2> <kolomtype> {(<lengte>)}{NOT NULL},…
)
De notatiewijze van de commando's in dit boek moeten we als volgt lezen:
- HOOFDLETTERS betekenen een letterlijk in te tikken woord
- kleine letters tussen < > wil zeggen een zelf in te vullen woord
- tekst tussen { } is optioneel
- een serie ..... geeft aan dat het gehele voorgaande stuk meerdere malen herhaald mag
worden
- alle andere leestekens zoals, en ( ) moeten op de aangegeven plaatsen gebruikt worden.
Gemakshalve gaan we hieruit van een nogal "kale" CREATE TABLE opdracht. In een latere
cursus zal nog worden stilgestaan bij de uitbreidingen op deze opdracht en de rol van de data
dictionaire.
Bij de bepaling van het kolomtype kunnen we kiezen uit verschillende mogelijkheden. De
belangrijkste typen zijn:
voor kolommen met decimale getallen
voor alfanumerieke kolommen
voor datumkolommen
voor alfanumerieke kolommen met zeer veel karakters
Bij DECIMAL kunnen we de lengte en eventueel het aantal decimalen aangeven.
Bij CHAR moeten we de lengte aangeven.
Naast deze standaardtypen komt (afhankelijk, van het RDBMS waar mee gewerkt wordt) nog
een groot aantal andere typen (VARCHAR, LONG VARCHAR, DECIMAL, FLOAT, INTEGER,
SMALLINT en dergelijke) voor, die echter niet meer dan variaties op deze vier basistypen zijn.
We zouden dus de volgende opdracht kunnen maken:
CREATE TABLE WERKNEMERS(
CODE CHAR(3) NOT NULL,
NAAM CHAR(15) NOT NULL,
VOORLETTERS CHAR(8),
VOORVOEGSEL CHAR(8),
ADRES CHAR(20),
POSTCODE CHAR(7),
WOONPLAATS CHAR(20),
TELEFOON CHAR(12),
DATUM_IN_D DATE,
SAL DECIMAL(8,2),
CHEF CHAR(3)
)
Hoofdstuk: Het opzetten van de database (DDL)
DECIMAL
CHAR
DATE
LONG
6
Database SQL
1 mei 2010
Hierdoor ontstaat er een tabel met een elftal kolommen waarmee we onze werknemers
kunnen beschrijven. Een aantal opvallende zaken zullen we eerst bespreken.
Bij een tweetal kolommen geven we de kwalificatie NOT NULL, dat wil zeggen dat deze kolom
ingevuld moet worden. Het is namelijk niet toegestaan dat een werknemer opgenomen wordt
die nog geen CODE heeft (denk aan de integriteit!) en bovendien stellen we vast dat van iedere
werknemer in ieder geval zijn of haar NAAM bekend moet zijn.
De volledige naam van iedere werknemer hebben we opgesplitst in een kolom NAAM, een
kolom VOORLETTERS en een kolom VOORVOEGSEL voornamelijk omdat dit bij het maken van
gesorteerde overzichten erg handig kan zijn. We zorgen er dan voor dat bij het alfabetiseren,
werknemer 'De Jonge' na 'Jansma' wordt geplaatst in plaats van voor 'Dekker'.
Ondanks het feit dat een telefoonnummer uit cijfers bestaat hebben we hier toch gezegd dat
een telefoonnummer van het type CHAR is. Dit heeft een tweetal redenen; in de eerste plaats
zorgen we er zo voor dat de nullen die vooraan staan bij een telefoonnummer niet weggehaald
worden (dus geen 20 in plaats van 020) en bovendien voorkomen we zo dat 020-1234567 de
waarde -1234547 toebedeeld krijgt.
Bij de kolom datum van indiensttreding (DATUM_IN_D) hebben we alleen het type van de
kolom (DATE) en niet de lengte opgegeven omdat de lengte door het RDBMS zelf bepaald is en
dus niet apart opgegeven hoeft te worden.
De kolom salaris (SAL) is van het type DECIMAL en heeft een lengteaanduiding 8,2. Dat wil
zeggen dat deze kolom in totaal 8 posities breed zal worden waarvan twee posities door de
decimalen in beslag zullen worden genomen.
De kolom CHEF bestaat uit een drietal karakters. Dit is uiteraard niet toevallig evenveel als de
kolom CODE omdat in deze kolom eenvoudig weg de CODE van de CHEF van de
desbetreffende werknemer wordt ingevuld. In de gegevensanalyse spreekt men dan wel van
een CODE in de rol van CHEF, met andere woorden deze CODE speelt, als het ware een beetje
toneel en heeft zich vermomd als CHEF.
Eigenlijk zou het CREATE commando voldoende moeten zijn voor het opzetten van een
database. Helaas is het zo dat we ten tijde van het opzetten van de database niet echt in de
toekomst kunnen kijken. Zo kan het voorkomen dat we ons bij de analyse van de situatie
vergist hebben in de mogelijke groei van een bepaalde waarde: (In Amerika zorgde de eerste
cheque boven de 9.999,99 dollar die de Social Security Agency moest boeken voor een
onkostenpost van tientallen Miljoenen dollars).
Om in staat te zijn een wijziging in een tabel aan te brengen zonder omslachtige ex- en import
operaties uit te hoeven voeren hebben we de beschikking over het ALTER TABLE commando.
Met behulp van de ALTER TABLE opdracht kunnen we verschillende soorten wijzigingen
aanbrengen. In deze paragraaf zullen we overigens niet ingaan op de beperkingen en andere
regels die door middel van ALTER TABLE in de data dictionaire kunnen worden vastgelegd. Dit
wordt nog in later hoofdstuk aan de orde gesteld.
Hoofdstuk: Het opzetten van de database (DDL)
De ALTER TABLE opdracht
7
Database SQL
1 mei 2010
In de eerste plaats kan het voorkomen dat de lengte of het type van een kolom gewijzigd moet
worden. In een aantal RDBMS-en kunnen we hier een optie van de ALTER TABLE opdracht voor
gebruiken:
ALTER TABLE <tabelnaam> MODIFY (<kolomnaam> <kolomtype>
[(<lengte>)] [ NULL| NOT NULL ], ...)
We zouden dus onze tabel aan kunnen passen door op te geven
ALTER TABLE WERKNEMERS MODIFY (SAL DECIMAL(9,2))
Na het geven van deze opdracht is in de tabel WERKNEMERS de kolom SAL een positie breder
geworden.
De toevoeging NOT NULL kan alleen gegeven worden als de desbetreffende kolom in de gehele
tabel in iedere rij een waarde heeft. Bovendien mag een bestaande kolom alleen kleiner
gemaakt worden of een ander kolomtype gegeven worden als in alle rijen van de tabel deze
kolom nog oningevuld (oftewel NULL) is.
Een tweede soort wijziging zou kunnen zijn dat er een kolom toegevoegd moet gaan worden.
Daarvoor gebruiken we de volgende opdracht:
ALTER TABLE <tabelnaam> ADD (<kolomnaam> <kolomtype>
[(<lengte>)] [ NULL | NOT NULL ], ...)
We zouden bijvoorbeeld op kunnen geven
ALTER TABLE WERKNEMERS ADD (SOFI_NUM CHAR(10))
Dit heeft tot gevolg dat aan de tabel WERKNEMERS een kolom SOFI NUM voor het sociaalfiscaal nummer van de werknemers wordt toegevoegd.
De DROP TABLE opdracht
Voor het weer verwijderen van tabellen is er in SQL een zeer eenvoudige en daardoor ook zeer
gevaarlijke opdracht
DROP TABLE <tabelnaam>
Als we dus op zouden geven
DROP TABLE WERKNEMERS
zou dit betekenen dat we in één regel een opdracht hebben ingetikt die een gehele tabel
zonder meer verwijdert. Voorzichtigheid is hier dus geboden!
Hoofdstuk: Het opzetten van de database (DDL)
Een kolom toevoegen die als NOT NULL gedefinieerd wordt kan alleen als de tabel nog geen
enkele rij bevat. De standaard waarde voor de MODIFY optie is NULL, met andere woorden
deze kolom mag oningevuld blijven.
8
Database SQL
1 mei 2010
Integriteitbewaking met de UNIQUE INDEX
Bij het definiëren van onze tabel zijn we er van uitgegaan dat in elk geval de CODE en de
NAAM van een werknemer bekend moeten zijn. Dat is een eerste stap in de richting van een
integere database.
Een probleem blijft echter dat we er bij sommige RDBMS-en niet voor kunnen zorgen dat in de
kolom CODE bij het toevoegen van een rij steeds een unieke code wordt gebruikt. Om er in die
gevallen voor te zorgen dat een sleutelkolom alleen unieke waarden kan bevatten, kunnen we
een UNIQUE INDEX aanmaken. Dat doen we door op te geven
CREATE [UNIQUE] INDEX <indexnaam> ON <tabelnaam>(.<kolomnaam>,
...)
UNIQUE is dus een optie van de CREATE INDEX opdracht omdat in SQL gebruik gemaakt wordt
van indices om het opzoeken van gegevens te versnellen. We zullen het principe van de index
verder behandelen in een van de volgende paragrafen.
Wat betreft het toekennen van een naam aan een index zijn we geheel vrij. Toch is het
verstandig om ook hier enige systematiek in acht te nemen. In de praktijk is. Bijvoorbeeld een
verkorte weergave van de tabelnaam en de kolom(men) waarop de index gedefinieerd is
uitermate handig.
We zouden dus kunnen opgeven
CREATE UNIQUE INDEX WERKNM_CODE ON WERKNEMERS(CODE)
Hierdoor wordt bij iedere nieuwe rij die toegevoegd wordt aan de
tabel WERKNEMERS eerst gecontroleerd of de waarde in de kolom CODE niet al bestaat in de
tabel WERKNEMERS.
CREATE UNIQUE INDEX WRKNM_NM_TEL ON WERKNEMERS(NAAM, TELEFOON)
Zodat bij iedere nieuwe rij eerst gecontroleerd wordt of de combinatie van NAAM en
TELEFOON niet al bestaat in de tabel.
In steeds meer implementaties is het op deze wijze bewaken van de integriteit overgenomen
door het opnemen van regels en beperkingen in de data dictionaire. Dit wordt in een alter
hoofdstuk aangegeven.
Indexeren
In de vorige paragraaf hebben we het gebruik van een UNIQUE INDEX aan de orde gesteld.
Daarmee konden we er voor zorgen dat er in een bepaalde kolom (of een bepaalde combinatie
van kolommen) alleen unieke waarden ingevuld konden worden. Dit is echter niet het enige
gevolg van het aanmaken van een (UNIQUE) INDEX.
Hoofdstuk: Het opzetten van de database (DDL)
Uit het feit dat we bij het opgeven van de kolomnaam ook meerdere kolomnamen op mogen
geven kunnen we al afleiden dat het dus ook mogelijk is om samengestelde sleutels op deze
manier uniek te houden. Zo zouden we op kunnen geven
9
Database SQL
1 mei 2010
Naast het bewaken van de uniciteit zorgt een index ook voor het versnellen van de
zoekoperaties.
We hebben al opgemerkt dat de UNIQUE INDEX een optie is van het algemene lNDEX
commando. Als we een index aanmaken betekent dit dat we de mogelijkheid creëren om de
desbetreffende tabel te benaderen via de index in plaats van het van begin tot einde
doorzoeken van de tabel. Er wordt als het ware een index zoals bij een boek aangemaakt
waardoor het RDBMS door gebruik te maken van deze index de gezochte rijen veel sneller
terug kan vinden.
Naast dit voordeel van de tijdwinst bij het opzoeken van rijen kan het aanmaken van indices
ook een nadeel hebben. Net als bij de index van een boek zal een wijziging in de tabel tot
gevolg hebben dat de index ook bijgewerkt moet worden. Bij het aanbrengen van wijzigingen
zal een index dus eerder tot tijdverlies dan tot tijdwinst leiden. Vandaar dat het van belang is
om slechts indices aan te maken op kolommen waar vaak op gezocht zal worden en niet op
kolommen die sterk aan wijzigingen onderhevig zijn.
Bovendien moeten we ons realiseren dat bij vrijwel alle RDBMS-en die met SQL benaderd
kunnen worden het onmogelijk is om het RDBMS te dwingen gebruik te maken van de index.
Er is een zogenaamde optimizer aanwezig die zelf zal bepalen of het gebruik van de index
nuttig is of niet.
Als we in de tabel WERKNEMERS dus versneld willen zoeken op grond van bijvoorbeeld de
CODE van de werknemers zouden we een index aan kunnen maken met
CREATE INDEX WERKN_CODE ON WERKNEMERS(CODE)
Het weer verwijderen van een INDEX kunnen we uitvoeren door gebruik te maken van de
opdracht
Hoofdstuk: Het opzetten van de database (DDL)
DROP INDEX <indexnaam>
1
0
Database SQL
1 mei 2010
VRAGEN EN OPDRACHTEN
Deze opdrachten en vragen kunnen alleen worden uitgeprobeerd op de database indien U
deze zelf heeft geïnstalleerd.
VRAGEN
1. Waarom zouden we bij het toevoegen van een kolom aan een bestaande tabel niet de
NOT NULL kwalificatie mee kunnen geven?
2. Waar zorgt de toevoeging UNIQUE voor bij de volgende index:
CREATE UNIQUE INDEX KL_NM_PC ON KLANTEN(NAAM, POSTCODE)
3. Waarom zou het onmogelijk zijn om een bestaande kolom smaller te maken?
OPDRACHTEN
1. Geef de opdracht in SQL voor het aanmaken van de tabel waar de gegevens van een
student kunnen worden opgeslagen. Zorg ervoor dat in ieder geval de naam, adres,
postcode, telefoonnummer, geboortedatum en datum van start van de studie worden
opgenomen. (Bepaal zelf het type en de lengte!)
2. Geef de opdracht in SQL om aan de tabel uit opgave 1 een kolom genaamd
EXPORTCODE van 4 karakters toe te voegen.
3. Geef de opdracht in SQL om deze EXPORTCODE vervolgens 1 karakter breder te
maken.
4. Geef de opdracht in SQL om een tabel KLANTEN aan te maken met daarin opgenomen
een alfanumerieke KLANTCODE kolom die altijd ingevuld moet zijn, een alfanumerieke
NAAM kolom, een numerieke CRED_LIMIET kolom en een datumkolom genaamd
KLANT_SINDS. Bepaal zelf de lengtes.
5. Geef de opdracht In SQL om bij de KLANTEN tabel een index aan te maken op de
kolom KLANTCODE.
Hoofdstuk:
6. Geef de opdracht in SQL om er met behulp van indexeren voor te zorgen dat de
combinatie van de kolommen KLANTCODE en NAAM in iedere rij uniek zal blijven.
1
1
Database SQL
1 mei 2010
Het werken met Gegevens (DML)
Het vullen van de tabel met behulp van INSERT
Voordat we ook maar iets kunnen doen met een tabel zullen er uiteraard eerst gegevens in
moeten staan. We zuilen dat hier doen met de INSERT opdracht. In de praktijk zal het INSERT
commando een ondergeschikte rol spelen omdat het zeer vaak veel eenvoudiger is om met
behulp van een applicatiegenerator een invoerscherm te maken zodat. de vrij omslachtige
wijze van werken bij de INSERT opdracht vermeden kan worden.
Met de INSERT opdracht kunnen we één rij tegelijk toevoegen aan een bepaalde tabel
INSERT INTO <tabelnaam> [(kolomnaam,...)] VALUES (waarde, ...)
Zo zouden we in de tabel WERKNEMERS zoals eerder aangemaakt een aantal rijen kunnen
inbrengen door gebruik te maken van
INSERT INTO WERKNEMERS VALUES ('10', 'BUCK', 'A.P.', 'DE',
'LINDELAAN 2', '1055 PP', 'AMSTERDAM', '020-6768087', '01-JAN80', 4567, '99')
INSERT INTO WERKNEMERS VALUES ('12', 'BRASSER', 'K.J.', NULL,
'LINDELAAN 18', '1055 PP', 'AMSTERDAM', '020-9874386',
'12-OCT-88', 2149, '20')
INSERT INTO WERKNEMERS VALUES ('18', 'VLIET', 'P.', 'VAN','KADE
34', '1056 KM', 'AMSTERDAM', '020-9321072',
'28-SEP-85',2638, '20')
INSERT INTO WERKNEMERS VALUES ('19', 'UMBGROVE', 'M.M.',NULL,
'TALMALAAN 3', '4351 JG', 'VLISSINGEN', '0118-439816','13-NOV87', 2988, '30')
INSERT INTO WERKNEMERS VALUES ('20', 'MAAS', 'L.C.',
NULL','BOSJESLAAN 3', '3085 HG', 'ROTTERDAM', '010-9859526',
'01-FEB-84', 3332, '10')
INSERT INTO WERKNEMERS VALUES ('25', 'NEVE', 'G.', 'DE',
'PRINSENGRACHT 20', '1048 GP', 'AMSTERDAM', '020-9865743', '15MAY-91', 3148, '40')
INSERT INTO WERKNEMERS VALUES ('26', 'GEEL', 'J.M.G.',
'VAN','PLEIN 43', '3568 JL', 'UTRECHT', '030-7385195', '01-DEC88',1921, '30')
INSERT INTO WERKNEMERS VALUES ('28', 'ZEEUW', 'A.J.', 'DE',
'JULlANASTRAAT 6', '5610 JP', 'EINDHOVEN', '040-5932182', '12AUG-86', 2981, '35')
Hoofdstuk: Het werken met Gegevens (DML)
INSERT INTO WERKNEMERS VALUES ('16', 'LIEVENSE', 'I.H.',
NULL,'HOOFDSTRAAT 3', '8948 KK', 'LEEUWARDEN', '0588916534','14-0CT-95', 3148, '30')
1
2
Database SQL
1 mei 2010
INSERT INTO WERKNEMERS VALUES ('30', 'MERK', 'J.', NULL,
'EIKENLAAN 12', '3086 KK', 'ROTTERDAM', '010-9734733', '01-MAR86',4749, '40')
INSERT INTO WERKNEMERS VALUES ('31', 'PAREE', 'G.M.', NULL,'KADE
44:, '1056 KM', 'AMSTERDAM', '020-9753264', '25-MAR-90', 2745,
'35')
INSERT INTO WERKNEMERS VALUES ('35', 'JONGE', 'L.M.',
'DE','GRACHT 11', '6222 AG', 'MAASTRICHT', '043-3324785', '30JUN-95', 2118, '40')
INSERT INTO WERKNEMERS VALUES ('40', 'WILLEGEN', 'W.M.I,'VAN',
'BEUKENLAAN 12', '3088 LM', 'ROTTERDAM', '010-9865843', '01-MAR78', 4988, '99')
INSERT INTO WERKNEMERS VALUES ('45', 'JOBSE', 'G.C.',
NULL,'SINGEL 128', '3088 JP', ~ ‘ROTTERDAM', '010-9434785', '15JUL-86',4716,'40')
INSERT INTO WERKNEMERS VALUES ('47', 'JANSMA', 'L.M.',
NULL,'SINGEL 48', '1038 JG', 'AMSTERDAM', '020-4343210', '14APR-84', 2144, '35')
INSERT INTO WERKNEMERS VALUES ('48', 'BOS', 'P.', NULL,
'BEUKENLAAN 18', '3088 LM', 'ROTTERDAM', '010-9324321, '28-NOV87', 2357, '60')
INSERT INTO WERKNEMERS VALUES ('52', 'MAAS', 'M.C.', 'VAN DER',
'HOGEWEG 12', '3078 KL', 'ROTTERDAM', '010-3544567','12-DEC-86',
2849, '60')
INSERT INTO WERKNEMERS VALUES ('60', 'VLIET', 'P.C.', 'VAN
DER','ORANJEPLEIN 3',
'5655 BG', 'EINDHOVEN', '040-9143421', '01-APR-79',3848, '10')
INSERT INTO WERKNEMERS VALUES ('99', 'KONING', 'C.', 'DE',
'SINGEL 2', '3088 JK', 'ROTTERDAM', '010-6493214', '01-JAN80',5624, NULL)
Uit het voorafgaande wordt meteen duidelijk dat dit een nogal omslachtige wijze van het
invoeren van rijen is. Ook wordt duidelijk dat we bij de INSERT opdracht een aantal regels in
acht moeten nemen.
Hoofdstuk: Het werken met Gegevens (DML)
INSERT INTO WERKNEMERS VALUES ('50', 'LOOF', 'J.G.', 'DE',
'PLEIN 12', '3568 JL', 'UTRECHT', '030-9678765', '01-AUG-86',
4328, '10')
1
3
Database SQL
1 mei 2010
Waarden die ingevuld moeten worden in een alfanumerieke (CHAR) kolom moeten met enkele
aanhalingstekens worden omgeven.
Waarden in DATE kolommen moeten in het formaat DD-MON-YY en tussen aanhalingstekens
ingevoerd worden.
Numerieke (DECIMAL) kolommen moeten zonder aanhalingstekens ingevoerd worden.
Indien een bepaalde kolom niet ingevuld hoeft te worden gebruiken we NULL.
De kolomnamen hoeven we alleen op te geven als we een volgorde hanteren die afwijkt van
de volgorde van de kolommen zoals we die gebruikt hebben bij de CREATE TABLE opdracht of
als we bepaalde kolommen niet willen invullen zonder steeds NULL te gebruiken. We zouden
bijvoorbeeld alleen de CODE en de NAAM van een werknemer in kunnen voeren door op te
geven
INSERT INTO WERKNEMERS (CODE,NAAM)VALUES ('80','JANSEN')
VRAGEN EN OPDRACHTEN
Deze vragen en opdrachten kunnen alleen worden uitgeprobeerd indien U zelf de database
heeft geïnstalleerd.
VRAGEN
1. Wat zijn de belangrijkste aandachtspunten bij het gebruik van respectievelijk CHAR,
NUMBER, DATE en NULL waarden in een INSERT opdracht?
OPDRACHTEN
1. Geef de INSERT opdracht voor het invoeren van de volgende rijen in de WERKNEMERS
tabel
54 P.KATS BEUKENLAAN 1243057 HG ROTTERDAM geen telefoon, in dienst per 1 april
1989 met een nog onbekend salaris, de chef wordt 30.
2. Geef een zo kort mogelijke lNSERT opdracht om de volgende rij aan de tabel toe te
voegen
71 K.SCHREURS, telefoon 0118-493218, nadere gegevens nog
niet bekend.
SPECIAL
Om de opdrachten van de volgende hoofdstukken te maken is het nodig dat je de database
netjes aanmaakt en invult. Dit kan met de opdrachten die we hierboven geleerd hebben.
Echter, het is waarschijnlijk dat er dan veel type fouten gemaakt zullen worden waardoor het
een en ander niet bepaald soepel zal verlopen. Er is een bestand gemaakt SQLCURSUS.TXT dat
alle opdrachten die nodig zijn netjes bevat. Je kunt dit importeren in je databasemanagement
programma. Ga in de documentatie van het RDBM na hoe dat moet en importeer het dan.
Hoofdstuk: Het werken met Gegevens (DML)
63 K.5MULDERS P.C..HOOFTSTRAAT 56 1033 KL AMSTERDAM telefoon 020-6843762,
in dienst met ingang van heden, salaris wordt 3567, de chef wordt 40.
1
4
Database SQL
1 mei 2010
Fundamentele opdrachten met SELECT
Met behulp van de SELECT opdracht zijn we in staat om een aantal fundamentele handelingen
te verrichten. We kunnen namelijk bepaalde kolommen uit de tabel opvragen (PROJECTIE),
bepaalde rijen uit de tabel selecteren (SELECTIE) en we kunnen gegevens uit meerdere
tabellen gecombineerd opvragen (JOIN). We zullen deze aspecten één voor één behandelen.
Bij de PROJECTIE gaat het er om dat we slechts bepaalde kolommen uit de tabel willen zien. In
de WERKNEMERS tabel zou dit bijvoor- beeld de NAAM, de WOONPLAATS en het
TELEFOONNUMMER van de werknemers kunnen zijn. In een figuur weergegeven ziet
PROJECTIE er als volgt uit
In SQL kunnen we een projectie uitvoeren door in een SELECT instructie slechts bepaalde
kolommen te noemen
SELECT NAAM,WOONPLAATS, TELEFOON FROM WERKNEMERS
Deze SELECT opdracht geeft meteen aan wat er minimaal voor moet komen in een dergelijke
opdracht. In de eerste plaats geven we aan welke kolommen we willen zien (de PROJECTIE
dus) en in de tweede plaats geven we na FROM aan uit welke tabel de kolommen moeten
komen.
Bij de keuze van de kolommen hoeven we geen rekening te houden met de volgorde waarin
deze voorkomen in de tabel, iedere volgorde is toegestaan zolang we de namen van de
kolommen maar juist opgeven. Als we alle kolommen van een tabel willen zien dan gebruiken
we een * .
Hoofdstuk: Het werken met Gegevens (DML)
PROJECTIE
1
5
Database SQL
1 mei 2010
Dus:
SELECT*
FROM WERKNEMERS
geeft een overzicht van alle kolommen (en alle rijen) uit de WERKNEMERS tabel.
Als we de informatie uit de tabel willen beperken tot bepaalde rijen (een SELECTIE uitvoeren)
dan doen we dit door achter het FROM gedeelte een voorwaarde gedeelte aan te geven met
behulp van WHERE. We zouden bijvoorbeeld informatie op kunnen vragen uit onze
WERKNEMERS tabel door alleen de werknemers uit UTRECHT te selecteren
SELECT *
FROM WERKNEMERS
WHERE WOONPLAATS = 'UTRECHT'
PROJECTIE
Bij het gebruik van een alfanumerieke constante in het WHERE gedeelte moeten we gebruik
maken van enkele aanhalingstekens om aan te geven dat het hier om een alfanumerieke
constante gaat. Dit geldt ook voor een datum constante. Numerieke constanten kunnen
zonder de enkele aanhalingstekens gebruikt worden. Dus
WHERE <kolomnaam> = 'CHAR constante'
WHERE <kolomnaam> = 'DATE constante'
WHERE <kolomnaam> = NUMBER constante
Uiteraard zal het heel vaak zo zijn dat we een SELECTIE en een PROJECTIE willen combineren.
Bijvoorbeeld als we van alle werknemers uit UTRECHT alleen de NAAM, de WOONPLAATS en
het TELEFOONNUMMER willen zien
Hoofdstuk: Het werken met Gegevens (DML)
Hierdoor worden alle rijen uit de tabel waarvoor geldt dat in de kolom WOONPLAATS de
waarde UTRECHT is ingevuld op ons scherm afgedrukt. Er is dus een SELECTIE uitgevoerd.
1
6
Database SQL
1 mei 2010
SELECT NAAM, WOONPLAATS, TELEFOON
FROM WERKNEMERS
WHERE WOONPLAATS = 'UTRECHT'
Hierdoor worden de projectie en de selectie gecombineerd.
SELECT+PROJECTIE
In veel gevallen zal het bovendien zo zijn dat we gegevens uit meerdere tabellen willen
combineren. Het proces van normaliseren leidt tenslotte al vrij snel tot een ware explosie van
het aantal tabellen.
Dat maakt de kans op redundantie vrij klein maar maakt het opvragen van gegevens er in veel
gevallen niet gemakkelijker op.
Het is vooral van belang om te weten in welke volgorde een relationele database (conceptueel
gezien uiteraard) de verschillende onderdelen van een SELECT opdracht verwerkt.
Als we een eenvoudige SELECT opdracht zoals in het voorafgaande formuleren, zal de
verwerking als volgt plaatsvinden: eerst wordt de tabel (of worden de tabellen) in het
werkgeheugen geplaatst, met andere woorden: eerst wordt het FROM gedeelte uitgevoerd.
Vervolgens zal er een selectie van rijen die aan de voorwaarde voldoen plaatsvinden (het
WHERE gedeelte dus) en tenslotte zal gekeken worden welke kolommen uiteindelijk op het
beeldscherm moeten worden gezet. Dat betekent dus dat bij een combinatie van gegevens uit
meerdere tabellen deze tabellen allereerst in het werkgeheugen worden geplaatst zonder dat
er een vorm van selectie heeft plaatsgevonden.
Als we gegevens uit meerdere tabellen willen combineren geven we dit aan door in het FROM
gedeelte de tabellen, gescheiden door komma's, te noemen. Als we weer terugkeren naar de
tabellen uit het eerste hoofdstuk zouden we ons voor kunnen stellen dat we een overzicht
Hoofdstuk: Het werken met Gegevens (DML)
Bij het combineren van gegevens uit meerdere tabellen (de JOIN) zullen we ons een aantal
zaken moeten realiseren.
1
7
Database SQL
1 mei 2010
willen hebben van alle uren die verschillende werknemers hebben besteed aan verschillende
projecten.
We zouden dus kunnen formuleren
SELECT *
FROM WERKNEMERS, WERK
Als we deze opdracht daadwerkelijk zo in zouden geven, zouden we het volgende resultaat
verkrijgen:
WERKNEMERSNAAM
WERKNEMERSPROJECTUREN
CODE
CODE
CODE
Jan
Jan
Jan
Jan
Jan
Irene
Irene
Irene
Irene
Irene
Inge
Inge
Inge
Inge
Inge
Karel
Karel
Kare1
Karel
Karel
12
34
12
56
34
12
34
12
56
34
12
34
12
56
34
12
34
12
56
34
110
110
120
130
120
110
110
120
130
120
110
110
120
130
120
110
110
120
130
120
28
14
12
23
16
28
14
12
23
16
28
14
12
23
16
28
14
12
23
16
We hebben dan het product van twee verzamelingen op ons scherm oftewel een cartesiaans
product. Dit wil zeggen dat elke rij uit de (eerste) tabel WERKNEMERS is gekoppeld met elke rij
van de (tweede) tabel WERK. Dit kan uiteraard niet de bedoeling zijn. We willen immers
gegevens uit twee tabellen met elkaar combineren die ook op dezelfde entiteiten betrekking
hebben. Dit kunnen we bereiken door deze rijen uit dit cartesiaans product te selecteren. Als
we aan de voorgaande opdracht toevoegen dat we alleen geïnteresseerd zijn in gegevens die
betrekking hebben op één en dezelfde werknemer, kunnen we dat als volgt formuleren
SELECT *
FROM WERKNEMERS, WERK
WHERE WERKNEMERS.WERKNEMERSCODE = WERK.WERKNEMERSCODE
Als we de opdracht zo formuleren wordt er nog steeds een cartesiaans product gemaakt maar
dit wordt alleen in het werkgeheugen gebruikt door het RDBMS. Als dit cartesiaans product
dan in het werkgeheugen is geplaatst, worden hier vervolgens alle rijen uit geselecteerd die
voldoen aan de gestelde voorwaarde in het WHERE gedeelte. Hierbij valt op dat we de
werknemerscode vooraf laten gaan door de naam van de tabel, dus
WERKNEMERS.WERKNEMERSCODE=WERK.WERKNEMERSCODE
Hoofdstuk: Het werken met Gegevens (DML)
12
12
12
12
12
34
34
34
34
34
56
56
56
56
56
67
67
67
67
67
1
8
Database SQL
1 mei 2010
en niet
WERKNEMERSCODE=WERKNEMERSCODE
omdat de kolom met als kolomkop WERKNEMERSCODE nu in feite tweemaal voorkomt in het
werkgeheugen en we dus aan moeten geven welke van de twee we bedoelen.
Het toevoegen van deze voorwaarde heeft tot gevolg dat we nu op ons scherm het volgende
te zien krijgen
WERKNEMERS
CODE
NAAM
WERKNEMERS PROJECT
CODE
CODE
UREN
12
12
34
34
56
Jan
Jan
Irene
Irene
Inge
12
12
34
34
56
28
12
14
16
23
110
120
110
120
130
En dit lijkt meer op wat we eigenlijk wilden weten. Als we dan bovendien nog een projectie
toepassen, kunnen we een aardig resultaat verkrijgen
SELECT
WERKNEMERS.WERKNEMERSCODE, NAAM, PROJECTCODE, UREN
FROM WERKNEMERS, WERK
WHERE WERKNEMERS.WERKNEMERSCODE=WERK.WERKNEMERSCODE
WERKNEMERSCODE
NAAM
PROJECTCODE
UREN
12
12
34
34
56
Jan
Jan
Irene
Irene
Inge
110
120
110
120
130
28
12
14
16
23
Nu we de fundamentele bewerkingen besproken hebben zullen we in de volgende paragrafen
nog eens wat gedetailleerder ingaan op allerlei aspecten van de SELECT instructie.
Hoofdstuk: Het werken met Gegevens (DML)
Geeft dan
1
9
Database SQL
1 mei 2010
VRAGEN
1. Welk woord gebruiken we altijd om voorwaarden te stellen aan de te selecteren rijen?
2. Hoe kunnen we een opgevraagd overzicht van rijen beperken tot bepaalde kolommen?
3. Hoeveel rijen zouden we op ons scherm krijgen als we van drie tabellen van ieder 80
rijen op zouden vragen
SELECT * FROM TABEL1, TABEL2, TABEL3
4. Wanneer moeten we gebruik maken van de combinatie tabelnaam.kolomnaam?
5. Noem de 3 fundamentele opdrachten die we met een SELECT kunnen uitvoeren. Geef
een korte uitleg over de werking ervan.
6. Geef aan wat er achtereenvolgens wordt uitgevoerd bij de volgende opdracht
SELECT A.a,A.b,B.a
FROM A, B
WHERE A.a=B.a
OPDRACHTEN
1. Geef de opdracht in SQL om alle gegevens uit de tabel KLANTEN op te vragen.
Hoofdstuk: Het werken met Gegevens (DML)
2. Geef de opdracht in SQL om alle gegevens op te vragen uit de tabellen KLANTEN en
BESTELLINGEN. (Zowel in de tabel KLANTEN als in de tabel BESTELLINGEN is er een
kolom KLANTCODE.)
2
0
Database SQL
1 mei 2010
DISTINCT
Weer uitgaande van de tabel WERKNEMERS zoals we die in een eerdere paragraaf hebben
gevuld zouden we een overzicht op kunnen vragen van alle woonplaatsen waar onze
werknemers wonen, Met het voorgaande nog in gedachten is deze vraag vrij snel in SQL te
formuleren
SELECT WOONPLAATS
FROM WERKNEMERS
Als we dit zo invoeren krijgen we het volgende resultaat
WOONPLAATS
Ondanks het feit, dat dit het enige juiste antwoord op de gestelde vraag is, zal het in veel
gevallen eerder de bedoeling zijn om een overzicht te produceren van alle verschillende
woonplaatsen uit de tabel WERKNEMERS. Ook dit is in SQL vrij eenvoudig te formuleren
SELECT DISTINCT WOONPLAATS
FROM WERKNEMERS
Dit zal het volgende resultaat opleveren
WOONPLAATS
AMSTERDAM
LEEUWARDEN
VLISSINGEN
ROTTERDAM
EINDHOVEN
MAASTRICHT
Door het toevoegen van DISTINCT zorgen we er voor dat er geen dubbele waarden afgedrukt
worden. Let wel: DISTINCT geldt per rij, dus als we zouden invoeren
Hoofdstuk: Het werken met Gegevens (DML)
AMSTERDAM
AMSTERDAM
LEEUWARDEN
AMSTERDAM
VLISSINGEN
ROTTERDAM
AMSTERDAM
UTRECHT
EINDHOVEN
ROTTERDAM
AMSTERDAM
MAASTRICHT
ROTTERDAM
ROTTERDAM
AMSTERDAM
ROTTERDAM
UTRECHT
ROTTERDAM
EINDHOVEN
ROTTERDAM
2
1
Database SQL
1 mei 2010
SELECT DISTINCT NAAM,WOONPLAATS
FROM WERKNEMERS
levert dit vrijwel alle namen en alle woonplaatsen uit de WERKNEMERS tabel op omdat deze
steeds als combinatie wel eenmalig voorkomen. (Welke combinatie van naam en woonplaats
komt nu nog steeds te vervallen?)
OPDRACHTEN
Geef een opdracht in SQL voor het opvragen van de volgende overzichten uit de WERKNEMERS
tabel
1. Alle namen van alle werknemers.
2. Alle namen slechts eenmaal. genoemd. 11
3. Alle combinaties van WOONPLAATS en POSTCODE eenmaal genoemd.
4. Alle salarissen.
5. Alle salarissen slechts eenmaal genoemd.
Hoofdstuk: Het werken met Gegevens (DML)
6. Alle waarden uit de DATUM_IN_D kolom.
2
2
Database SQL
1 mei 2010
Rekenen met kolominhouden
Het is ook mogelijk om berekeningen uit te voeren met te selecteren kolommen alvorens ze op
het scherm af te drukken. We gebruiken daarvoor {involgorde van prioriteit) de operatoren
* en / vermenigvuldigen en delen
+ en -optellen en aftrekken
De prioriteit is uiteraard te beïnvloeden door gebruik te maken van haakjes ().
We mogen deze operatoren gebruiken om berekeningen uit te voeren met een kolom en een
constante, twee kolommen en {hoewel dat niet zo erg nuttig is) twee constanten.
Als we naast het maandsalaris ook het jaarsalaris van de WERKNEMERS willen zien kunnen we
dat opvragen door
SELECT NAAM,SAL,SAL * 12
FROM WERKNEMERS
BUCK
MAAS
MERK
WILLEGEN
KONING
LOOF
VLIET
NEVE
JONGE
JOBSE
VLIET
BRASSER
BOS
MAAS
JANSMA
PAREE
ZEEUW
LIEVENSE
UMBGROVE
GEEL
4567
3332
4749
4988
5624
4328
3848
3148
2118
4716
2638
2149
2357
2849
2144
2745
2981
3148
2988
1921
54804
39984
56988
59856
67488
51936
46176
37776
25416
56592
31656
25788
28284
34188
25728
32940
35772
37776
35856
23052
Als we nog een tweede numerieke kolom in onze tabel zouden hebben (COMMISSIE
bijvoorbeeld) zouden we een overzicht kunnen krijgen door
SELECT NAAM,SAL,COMMISSIE,SAL+COMMISSIE
FROM WERKNEMERS
We moeten hierbij wel waarschuwen voor het feit dat een optelling waar een NULL waarde bij
betrokken is ook de waarde NULL oplevert. Immers: als we iets onbekends ergens bij optellen,
kunnen we alleen maar aangeven dat dit als uitkomst iets op zal leveren dat ook onbekend is.
Met andere woorden: alle WERKNEMERS zonder COMMISSIE krijgen de waarde NULL als
Hoofdstuk: Het werken met Gegevens (DML)
Dat geeft ons het volgende overzicht .
NAAM
SAL SAL * 12
2
3
Database SQL
1 mei 2010
uitkomst in de laatste kolom van bovenstaand overzicht (Met de functie NVL(<kolomnaam>,O)
die iedere NULL waarde omzet in het getal 0, kunnen we dit in sommige RDBMS-en oplossen.)
Vaak leiden rekenkundige bewerkingen tot lelijke en lange kolomkoppen in onze overzichten.
Dit kunnen we oplossen door in het SELECT gedeelte na de rekenkundige formulering een
spatie, gevolgd door een alternatieve kolomkop op te geven.
SELECT NAAM,SAL PER_MAAND,SAL *12 PERJAAR
FROM WERKNEMERS
Dit ziet er meteen al wat fraaier uit dan de formulering zonder alternatieve kolomkoppen.
NAAM
PER_MAAND PER_JAAR
BUCK
MAAS
MERK
WILLEGEN
KONING
LOOF
VLIET
NEVE
JONGE
JOBSE
VLIET
BRASSER
BOS
MAAS
JANSMA
PAREE
ZEEUW
LIEVENSE
UMBGROVE
GEEL
4567
3332
4749
4988
5624
4328
3848
3148
2118
4716
2638
2149
2357
2849
2144
2745
2981
3148
2988
1921
54804
39984
56988
59856
67488
51936
46176
37776
25416
56592
31656
25788
28284
34188
25728
32940
35772
37776
35856
23052
1. De naam en het weeksalaris (salaris maal 3 gedeeld door 13) onder de kolomkop
WEEKSAL van iedere werknemer.
2. De naam en het salaris inclusief een op handen zijnde salarisverhoging van 2 % onder
de kolomkop NWSAL.
3. De naam en het totaal aan salaris inclusief de in vorige paragraaf genoemde kolom
COMMISSIE per jaar van alle werknemers.
4. De naam en de bonus (onder de kolomkop BONUS) voor iedere werknemer. Oe bonus
wordt berekend door het aantal jaren in dienst (af te leiden uit de numerieke kolom
JAAR_IN_O) te vermenigvuldigen met 1 % van het salaris.
Hoofdstuk: Het werken met Gegevens (DML)
OPDRACHTEN
Geef een opdracht in SOL voor het opvragen van de volgende overzichten uit de WERKNEMERS
tabel
2
4
Database SQL
1 mei 2010
Operatoren in het WHERE gedeelte.
Tot nu toe hebben we alleen nog maar gebruik gemaakt van het = teken om voorwaarden te
stellen aan de te selecteren rijen. Uiteraard hebben we ook andere operatoren tot onze
beschikking. We kunnen gebruik maken van het < of het > teken om andersoortige
voorwaarden te stellen. Bijvoorbeeld alle namen van werknemers met een salaris van meer
dan 3000 Euro:
SELECT NAAM
FROMWERKNEMERS
WHERE SAL > 3000
Het < of > teken kunnen we ook gebruiken om twee kolommen met elkaar te vergelijken in
plaats van het vergelijken van een kolom met een constante zoals in het voorgaande
voorbeeld. Hoewel we niet kunnen zeggen dat dit nu zo'n voor de hand liggende vraag is,
zouden we kunnen vragen om de namen van alle werknemers met een code die groter is dan
de code van hun chef
Ondanks het feit dat deze opdracht in dit geval het juiste antwoord oplevert moeten we toch
waarschuwen voor het gebruik van het < en het > teken bij alfanumerieke ((HAR) kolommen.
Omdat de ASCII tabel (gelukkig) onderscheid maakt tussen hoofdletters en kleine letters, kan
dit nog wel eens tot problemen leiden.
Bovendien wordt er nu lexicografisch vergeleken; dat wil zeggen dat eerst gekeken zal worden
naar het eerste teken, als dit gelijk is wordt gekeken naar het volgende teken enzovoort. Dat is
een prima uitgangspunt voor het indelen van bijvoorbeeld het telefoonboek maar het strookt
niet met ons numerieke positiestelsel omdat daarbij de waarde 80 kleiner zal zijn dan 100
terwijl bij een lexicografische vergelijking we bij het eerste teken al constateren dat de 8 in de
ASCII tabel een hogere waarde heeft dan de 1 en dat daarmee de waarde 80 dus groter is dan
de waarde 100! Bij numerieke (NUMBER) kolommen leveren deze operatoren vanzelfsprekend
geen enkel probleem op.
Als we het < of > teken willen combineren met het = teken, doen we dit eenvoudigweg door ze
achter elkaar te plaatsen
SELECT NAAM
FROM WERKNEMERS
WHERE SAL >= 3000
De volgorde van deze twee tekens staat vast, met andere woorden het is niet toegestaan om
=> te gebruiken in plaats van >= .
De 'ongelijk aan' operator wordt_in de verschillende RDBMS-en op verschillende wijzen
voorgesteld. De meest voorkomende vormen zijn <>, != en ^= . In dit boek zullen we het !=
teken gebruiken.
Zo kunnen we dus alle namen van werknemers die niet in ROTTERDAM wonen opvragen door
Hoofdstuk: Het werken met Gegevens (DML)
SELECT NAAM
FROM WERKNEMERS
WHERE CODE > CHEF
2
5
Database SQL
1 mei 2010
SELECT NAAM
FROM WERKNEMERS
WHERE WOONPLAATS != 'ROTTERDAM'
OPDRACHTEN
Geef een opdracht in SQL voor het opvragen van de volgende overzichten uit de WERKNEMERS
tabel
1. Alle namen en telefoonnummers van werknemers uit AMSTERDAM .
2. Alle namen, adressen en woonplaatsen van werknemers die minder verdienen dan
2600 Euro.
3. Alle namen van werknemers die een naam hebben die in het telefoonboek na de naam
JANSEN komt.
4. De woonplaatsen van alle werknemers die niet voor chef 40 werken.
5. De salarissen van alle werknemers die uit MAASTRICHT komen.
6. De namen en adressen van alle werknemers die na 1 januari 1988 in dienst zijn
gekomen.
7. De namen en 10% van het salaris (onder de kolomkop SAL_DEEL) van alle werknemers
die niet in ROTTERDAM wonen.
8. Alle woonplaatsen (zonder dubbelen) van werknemers die voor 31 december 1987 in
dienst zijn gekomen.
9. Alle namen en telefoonnummers van werknemers met een postcode boven 3088.
Hoofdstuk: Het werken met Gegevens (DML)
10. Alle namen van werknemers die niet meer dan 3500 Euro verdienen .
2
6
Database SQL
1 mei 2010
Het combineren van operatoren met AND en OR
Vaak zullen we niet kunnen volstaan met het stellen van één voorwaarde maar zullen we
meerdere voorwaarden willen combineren.
In SQL kunnen we dan gebruik maken van AND en OR.
Zo zouden we ons af kunnen vragen welke werknemers uit ROTTERDAM aangenomen zijn voor
1 januari 1987.
SELECT NAAM
FROM WERKNEMERS
WHERE WOONPLAATS = 'ROTTERDAM' AND
DATUM_IN_D < '01-JAN-87'
Dat is een geheel andere vraag dan de vraag welke werknemers uit ROTTERDAM komen OF
voor 1 januari 1987 zijn aangenomen
SELECT NAAM
FROM WERKNEMERS
WHERE WOONPLAATS = 'ROTTERDAM' OR
DATUM_IN_D < '01-JAN-87'
Bij het gecombineerd gebruiken van de AND en OR operatoren moeten we enige
voorzichtigheid in acht nemen.
Stel dat we een overzicht willen van alle werknemers die voor 1 januari 1987 in dienst zijn
gekomen en uit ROTTERDAM of uit UTRECHT komen, dan levert de opdracht
niet het juiste antwoord op. Zo geformuleerd vragen we immers om de namen van alle
werknemers die voor 1 januari 1987 in dienst zijn gekomen en in ROTTERDAM wonen,
aangevuld met de namen van werknemers die in UTRECHT wonen.
We kunnen dit probleem op twee manieren oplossen
SELECT NAAM
FROM WERKNEMERS
WHERE DATUM_IN_D < '0l-JAN-87' AND
WOONPLAATS = 'ROTTERDAM! OR
DATUM_IN_D < '01-JAN-87'AND
WOONPLAATS = 'UTRECHT'
of
SELECT NAAM
FROM WERKNEMERS
WHERE DATUM_IN_D < '01-JAN-87! AND
(WOONPLAATS = 'ROTTERDAM' OR
WOONPLAATS = !UTRECHT')
In veel gevallen zullen we, vanwege de kortere formulering, voor de tweede oplossing kiezen:
het gebruik van haakjes.
Hoofdstuk: Het werken met Gegevens (DML)
SELECT NAAM
FROM WERKNEMERS
WHERE DATUM_IN_D < '01-JAN-87' AND
WOONPLAATS = 'ROTTERDAM' OR
WOONPLAATS = 'UTRECHT'
2
7
Database SQL
1 mei 2010
OPDRACHTEN
Geef een opdracht in SQL voor het opvragen van de volgende overzichten uit de WERKNEMERS
tabel
1. De namen van alle werknemers die in UTRECHT wonen en een salaris hebben van
meer dan 3000 Euro.
2. De namen van alle werknemers met een postcode tussen (inclusief de grens waarden)
3050 en 3100.
3. De namen van alle werknemers met een salaris beneden de 2500 Euro of een salaris
boven de 4000 Euro.
4. De namen van alle werknemers met een salaris tussen de 2500 en 4000 Euro.
5. De namen en woonplaatsen van alle werknemers met als woonplaats ROTTERDAM en
als postcode 3088 JP of 3085 HG.
6. De namen van alle werknemers met als chef chef nummer 99 of chef nummer 20 en
als salaris een salaris van meer dan 4000 Euro of minder dan 2500 Euro.
7. De code en de naam van alle werknemers die niet voor chef 40 werken of een salaris
tussen 3000 en 4000 Euro hebben.
8. De naam, woonplaats en datum van indiensttreding van alle werknemers die tussen 1
januari 1987 en 31 december 1988 in dienst zijn gekomen of in AMSTERDAM wonen.
9. De namen van alle werknemers die in UTRECHT wonen of een salaris hebben tussen
2100 en 3000 Euro.
Hoofdstuk: Het werken met Gegevens (DML)
10. De namen van alle werknemers die niet in ROTTERDAM of in UTRECHT wonen, niet
voor chef 99 werken en een salaris tussen 2000 en 3000 Euro hebben.
2
8
Database SQL
1 mei 2010
Het gebruik van NOT
Naast de != operator kunnen we ook gebruik maken van NOT om een ontkenning te
formuleren. Dit wil echter niet zeggen dat de NOT operator een zelfde werking heeft als de !=
operator!!
We zouden ons bijvoorbeeld af kunnen vragen welke werknemers niet in ROTTERDAM of
AMSTERDAM wonen.
Als we dat proberen te formuleren als
SELECT NAAM
FROM WERKNEMERS
WHERE WOONPLAATS != 'ROTTERDAM' OR
WOONPLAATS != 'AMSTERDAM'
hebben we weliswaar een ontkennende operator in een met OR verbonden stel voorwaarden
geplaatst maar deze opdracht zal alle werknemers uit de WERKNEMERS tabel op ons scherm
zetten omdat voor alle werknemers geldt dat hun woonplaats of ongelijk aan AMSTERDAM of
ongelijk aan ROTTERDAM is; dat geldt zelfs voor ROTTERDAM en AMSTERDAM zelf.
De vraag is wel te beantwoorden met
SELECT NAAM
FROM WERKNEMERS
WHERE NOT (WOONPLAATS = 'ROTTERDAM' OR
WOONPLAATS = 'AMSTERDAM')
De NOT operator heeft een hogere prioriteit dan de AND operator, die op zijn beurt weer
boven de OR operator gaat.
A
B
NOT A
A AND B
A OR B
WAAR
ONWAAR
ONWAAR
WAAR
WAAR
WAAR
ONWAAR
ONWAAR
ONWAAR
WAAR
WAAR
ONBEKEND
ONWAAR
ONBEKEND
WAAR
ONWAAR
WAAR
WAAR
ONWAAR
WAAR
ONWAAR
ONWAAR
WAAR
ONWAAR
ONWAAR
ONWAAR
ONBEKEND
WAAR
ONBEKEND
ONBEKEND
ONBEKEND
WAAR
ONBEKEND
ONBEKEND
WAAR
ONBEKEND
ONWAAR
ONBEKEND
ONWAAR
ONBEKEND
ONBEKEND
ONBEKEND
ONBEKEND
ONBEKEND
ONBEKEND
Hoofdstuk: Het werken met Gegevens (DML)
In de volgende evaluatietabel kunnen we zien hoe de NOT, AND en OR operatoren gebruikt
moeten worden. Met ONBEKEND wordt bedoeld dat de waarde niet is ingevuld oftewel NULL
is.
2
9
Database SQL
1 mei 2010
VRAGEN EN OPDRACHTEN
VRAGEN
Wat is het verschil tussen de volgende twee opdrachten
SELECT NAAM
FROM WERKNEMERS
WHERE CHEF != '99' OR CHEF = '40'
SELECT NAAM
FROM WERKNEMERS
WHERE NOT (CHEF = '99' OR (CHEF = '40')
OPDRACHTEN
Geef een opdracht in SQL voor het opvragen van de volgende overzichten uit de WERKNEMERS
tabel.
1. Alle namen van werknemers die niet voor 1 april 1988 in dienst zijn gekomen.
2. Alle namen van werknemers die een salaris hebben dat niet tussen de 2500 en 3500
Euro ligt.
3. Alle namen van de werknemers die niet in MAASTRICHT of UTRECHT wonen en niet
voor chef 40 of chef 99 werken.
4. Alle namen van werknemers die niet als chef ‘chef 99’ of ‘chef 20’ hebben en een
salaris van meer dan 4000 of minder dan 2000 Euro hebben.
Hoofdstuk: Het werken met Gegevens (DML)
5. Alle namen van werknemers die niet in 1988 in dienst zijn gekomen.
3
0
Database SQL
1 mei 2010
BETWEEN
Als we op zoek zijn naar rijen uit de tabel waarbij de waarde van een kolom tussen twee
waarden ligt, zouden we gebruik kunnen maken van >= en <= gekoppeld met AND. Zo zouden
we de namen van alle werknemers met een salaris tussen de 2500 en de 3000 Euro op kunnen
vragen met
SELECT NAAM
FROM WERKNEMERS
WHERE SAL >= 2500 AND
SAL <=3000
Voor dit soort vragen kent SQL de BETWEEN operator:
SELECT NAAM
FROM WERKNEMERS
WHERE SAL BETWEEN 2500 AND 3000
Deze formulering is overzichtelijker dan de voorgaande met de >= en <= tekens. Wel moeten
we ons realiseren dat BETWEEN ...AND ...niet letterlijk TUSSEN ...EN ...betekent omdat ook de
grenswaarden meegenomen worden. Uiteraard kunnen we dit oplossen. Door te formuleren
BETWEEN 2501 AND 2999 of iéts dergelijks. Met behulp van de BETWEEN operator in
combinatie met NOT kunnen we uiteraard ook vragen stellen als: Welke werknemers hebben
een salaris dat niet tussen de 2500 en 3000 Euro ligt.
SELECT NAAM
FROM WERKNEMERS
WHERE SAL NOT BETWEEN 2500 AND3000
Geformuleerd zonder gebruik te maken van de BETWEEN operator zouden we moeten stellen:
Merk op dat in dit geval gebruik gemaakt wordt van OR om de twee voorwaarden aan elkaar
te koppelen.
OPDRACHTEN
Geef een opdracht in SQL voor het opvragen van de volgende overzichten uit de WERKNEMERS
tabel
1. Alle namen van werknemers die in dienst gekomen zijn tussen 1 januari 1985 en 31
december 1986.
2. Alle namen van werknemers die een salaris tussen 3500 en 4500 Euro hebben en in
ROTTERDAM wonen.
3. Alle namen van werknemers die een salaris hebben dat niet tussen 4000 en 5000 Euro
ligt of in UTRECHT wonen.
Hoofdstuk: Het werken met Gegevens (DML)
SELECT NAAM
FROM WERKNEMERS
WHERE SAL < 2500 OR
SAL > 3000
3
1
Database SQL
1 mei 2010
IN
Vaak zullen we op zoek zijn naar rijen waarbij een bepaalde kolom gelijk moet zijn aan een
aantal mogelijke waarden. We zouden bijvoorbeeld op zoek kunnen zijn naar alle werknemers
die in ROTTERDAM, AMSTERDAM of UTRECHT wonen. We kunnen dit vrij eenvoudig
formuleren door te vragen
SELECT NAAM
FROM WERKNEMERS
WHERE WOONPLAATS = 'ROTTERDAM' OR
WOONPLAATS = 'AMSTERDAM' OR
WOONPLAATS =}UTRECHT'
Het zal duidelijk zijn dat dit, zeker bij herhaald gebruik van dit soort samengestelde
voorwaarden, niet erg prettig werkt. Gelukkig hebben we de beschikking over de IN operator
waarmee we dergelijke vragen vrij eenvoudig op kunnen lossen
SELECT NAAM
FROM WERKNEMERS
WHERE WOONPLAATS IN ('ROTTERDAM', 'AMSTERDAM','UTRECHT')
Met behulp van de IN operator kunnen we dus aan een kolom de voorwaarde stellen dat de
daar ingevulde waarde voor moet komen in een reeks van waarden die we, gescheiden door
komma's, tussen haakjes plaatsen na de IN operator.
Het spreekt voor zich dat we ook hier weer gebruik kunnen maken
van NOT om de voorwaarde ontkennend te maken.
OPDRACHTEN
Geef een opdracht in SQL voor het opvragen van de volgende overzichten uit de WERKNEMERS
tabel
2. De namen van werknemers met als code 10, 12 of 60 en een salaris tussen de 3500 en
5000 Euro.
3. De namen van werknemers die in UTRECHT of MAASTRICHT wonen en niet voor chef
99 of chef 40 werken
4. De namen van werknemers die meer dan 4000 Euro verdienen en in ROTTERDAM,
UTRECHT of MAASTRICHT wonen.
5. De namen van werknemers die niet in AMSTERDAM of UTRECHT wonen en in 1988 in
dienst zijn gekomen.
Hoofdstuk: Het werken met Gegevens (DML)
1. De namen van werknemers die voor chef 99, 40 of 30 werken.
3
2
Database SQL
1 mei 2010
LIKE
In sommige gevallen krijgen we te maken met voorwaarden die niet zo gemakkelijk te vangen
zijn in vraagstellingen zoals we die tot nu toe behandeld hebben. Met name geldt dit voor
vragen als: welke werknemers hebben een naam die begint met een 'V' of hebben een naam
met als derde letter een' A ' ? Voor dit soort vragen maken we gebruik van de LIKE operator
tezamen met de % en _ tekens.
Het procentteken (%) staat daarbij voor een willekeurige rij lettertekens terwijl het
onderstrepingsteken (_) staat voor een willekeurig letterteken. Bovenstaande vragen zijn dus
als volgt te formuleren:
SELECT NAAM
FROM WERKNEMERS
WHERE NAAM LIKE 'V%'
en
SELECT NAAM
FROM WERKNEMERS
WHERE NAAM LIKE '__A%'
Zo kunnen we dus ook de voorwaarde stellen dat de naam niet mag bestaan uit 5 lettertekens
door gebruik te maken van:
SELECT NAAM
FROM WERKNEMERS
WHERE NAAM NOT LIKE '_____'
1. Alle namen van werknemers met een naam beginnend met een B.
2. Alle namen van werknemers met een naam met als vijfde letter een E.
3. Alle namen van werknemers met een naam waar op de laatste plaats niet de letter E
staat.
4. Alle namen van werknemers met een naam van vier letters.
5. Alle woonplaatsen die niet eindigen op 'DAM'.
6. Alle namen van werknemers die in een 'LAAN' wonen (dat wil zeggen: niet in een
straat of plein of iets dergelijks).
7. Alle namen van werknemers met een postcode die begint met 30.
Hoofdstuk: Het werken met Gegevens (DML)
OPDRACHTEN
Geef een opdracht in SQL voor het opvragen van de volgende overzichten uit de WERKNEMERS
tabel
3
3
Database SQL
1 mei 2010
NULL
Als we op zoek zijn naar rijen in een tabel waarbij we als voorwaarde stellen dat een bepaalde
ko1om oningevuld moet zijn, met andere woorden dat deze kolom de waarde onbekend
oftewel NULL moet hebben, maken we gebruik van de ISNULL voorwaarde.
We zouden bijvoorbeeld kunnen kijken welke werknemers geen CHEF hebben door in te
voeren:
SELECT NAAM
FROM WERKNEMERS II
WHERE CHEF IS NULL
We dienen ons (zoals reeds opgemerkt) goed te realiseren dat de NULL waarde betekent
onbekend wat dus niet hetzelfde is als de waarde 0. Zo zal de opdracht
SELECT NAAM
FROMWERKNEMERS
WHERE CHEF <= '99'
niet alle rijen uit de tabel WERKNEMERS selecteren omdat de niet ingevulde waarde bij
werknemer DE KONING niet kleiner is dan de waarde '99' maar eenvoudigweg ONBEKEND is
zodat deze vraagstelling slechts 19 van de 20 rijen oplevert.
OPDRACHTEN
Geef een opdracht in SQL voor het opvragen van de volgende overzichten uit de WERKNEMERS
tabel
1. De namen van werknemers die geen voorvoegsels bij hun naam hebben.
3. De namen van werknemers waarvan het telefoonnummer onbekend is.
4. De namen van werknemers waarvan het salaris of de chef (nog) riet bekend is.
5. De namen van werknemers waarvan het salaris (nog) niet bekend is maar die wel een
chef hebben.
Hoofdstuk: Het werken met Gegevens (DML)
2. De namen van werknemers die wel een chef hebben.
3
4
Database SQL
1 mei 2010
ORDER BY
Als we het resultaat van een bepaalde vraagstelling ook nog willen
sorteren, kunnen we gebruik maken van de opdracht ORDER BY.
Deze optie wordt altijd als laatste onderdeel van een SELECT opdracht opgegeven. Eigenlijk is
het niets anders dan een laatste bewerking van de geselecteerde rijen. Als we de namen van
alle werknemers uit ROTTERDAM, alfabetisch geordend, willen zien gebruiken we
SELECT NAAM
FROM WERKNEMERS
WHERE WOONPLAATS ='ROTTERDAM'
ORDER BY NAAM
Het is ook mogelijk om op meer dan één waarde te ordenen:
SELECT NAAM
FROM WERKNEMERS
ORDER BY NAAM,SAL
Dit zal de namen van de werknemers geordend op naam (en bij gelijke namen op salaris)
weergeven. Daarmee meteen aangevend dat het ordenen dus zowel op alfanumerieke als
numerieké kolommen kan gebeuren. Dat geldt overigens ook voor datumkolommen.
Uiteraard geldt ook hier weer het gevaar van een lexicografische ordening van alfanumerieke
waarden die uit cijfers bestaan.
Een apart probleem vormen de NULL waarden bij het gebruik van ORDER BY. Bij verschillende
RDBMS-en wordt hier verschillend mee omgegaan. In ORACLE bijvoorbeeld komen de NULL
waarden altijd eerst, of er nu oplopend of aflopend wordt gesorteerd. Dat betekent dus dat bij
de opdracht
SELECT NAAM
FROM WERKNEMERS
ORDER BY CHEF
werknemer DE KONJNG als eerste op het scherm zal komen, ook als we opgeven
SELECT NAAM
FROM WERKNEMERS
ORDER BY CHEF DESC
Hoofdstuk: Het werken met Gegevens (DML)
We kunnen deze volgorde ook omdraaien (van Z naar A laten sorteren) door achter ORDER BY
NAAM DESC (van DESCENDING) op te geven. Om de sorteervolgorde van A naar Z te laten
lopen zouden we ASC (van ASCENDING) op kunnen geven maar aangezien dat de default (door
het systeem gekozen) volgorde is doen we dit meestal niet.
3
5
Database SQL
1 mei 2010
OPDRACHTEN
Geef een opdracht in SQL voor het opvragen van de volgende overzichten uit de WERKNEMERS
tabel
1. De namen van alle werknemers oplopend geordend naar hun code.
2. Alle woonplaatsen slechts eenmaal genoemd, alfabetisch aflopend geordend.
3. Alle namen van alle werknemers, aflopend geordend naar salaris.
4. Alle namen van alle werknemers, geordend naar datum van indiensttreding.
Hoofdstuk: Het werken met Gegevens (DML)
5. Alle namen van alle werknemers met een salaris tussen 2000 en 4000 Euro, geordend
naar woonplaats en per woonplaats naar naam.
3
6
Database SQL
1 mei 2010
GROUP BY, HAVING, COUNT, AVG, SUM, MAX en MIN
De GROUP BY instructie zorgt er voor dat bepaalde rijen gegroepeerd worden zodat we
berekeningen en selecties kunnen uitvoeren met groepen rijen in plaats van individuele rijen.
We zullen ons eerst eens af gaan vragen hoe de GROUP BV instructie nu eigenlijk werkt.
Omdat de GROUP BV instructie onmiddellijk na de WHERE component wordt uitgevoerd
kunnen we ons het volgende voorstellen.
We zouden van de rijen in de tabel WERKNEMERS een aantal gegroepeerde rijen kunnen
maken, bijvoorbeeld per WOONPLAATS. Om dit te bereiken zouden we dus na de WHERE
component toe moeten voegen
GROUP BY WOONPLAATS
Het gevolg hiervan is dat er als het ware per woonplaats een aantal rijen tot één rij
gecombineerd worden. Dit betekent automatisch dat we met een opdracht als
SELECT NAAM,WOONPLAATS FROM WERKNEMERS
GROUP BY WOONPLAATS
NAAM
WOONPLAATS
BUCK,BRASSER, VLIET,NEVE,PAREE,JANSMA
UMBGROVE
LIEVENSE
MMS,MERK, WILLEGEN,JOBSE,BOS, MMS,KONING
GEEL,LOOF
ZEEUW, VLIET
JONGE
AMSTERDAM
VLISSINGEN
LEEUWARDEN
ROTTERDAM
UTRECHT
EINDHOVEN
MAASTRICHT
Het op het scherm zetten van de woonplaatsen is niet zo'n probleem. Maar wat moet er nu
afgedrukt worden bij NAAM ?? Dit kan dus niet
We zullen er dus rekening mee moeten houden dat we bij de GROUP BY optie alleen vragen
om die kolommen waar op gegroepeerd wordt of gebruik maken van de zogenaamde GROUP
FUNCTIES. De GROUP FUNCTIES die we in iedere SQL implementatie aan kunnen treffen zijn:
COUNT
AVG
SUM
MAX
MIN
Hoofdstuk: Het werken met Gegevens (DML)
niets kunnen beginnen. Immers er wordt gegroepeerd, dus eigenlijk ontstaat er iets als het
volgende
3
7
Database SQL
1 mei 2010
Count
We zouden ons bijvoorbeeld af kunnen vragen hoeveel werknemers er in iedere plaats wonen
SELECT WOONPLAATS,COUNT(*)
FROM WERKNEMERS
GROUP BV WOONPLAATS
Dit heeft tot gevolg dat er bij het tussen resultaat gekeken zal worden hoeveel rijen er in
iedere groep zitten (we geven door het* teken aan dat het aantal rijen geteld moet worden)
en dat de uitkomst op het scherm afgedrukt zal worden. Dat geeft dan het volgende resultaat
WOONPLAATS
AMSTERDAM
VLISSINGEN
LEEUWARDEN
ROTTERDAM
UTRECHT
EINDHOVEN
MAASTRICHT
COUNT(*)
6
1
1
7
2
2
1
We kunnen COUNT ook gebruiken om alleen het aantal ingevulde waarden per kolom te
tellen. We gebruiken dan de kolomnaam in plaats van het * teken.
SELECT WOONPLAATS,COUNT(CHEF)
FROM WERKNEMERS
GROUP BY WOONPLAATS
Geeft ons per woonplaats het aantal werknemers met een CHEF. Met andere woorden:
ROTTERDAM zal dan door het getal 6 in plaats van 7 worden vergezeld omdat de in
ROTTERDAM woonachtige DE KONING geen CHEF heeft en in dit geval dus niet meetelt.
SELECT WOONPLAATS,AVG(SAL)
FROM WERKNEMERS
GROUP BY WOONPLAATS I
AVG berekent het gemiddelde en houdt daarbij rekening met het feit dat niet ingevulde
kolommen (NULL waarden) genegeerd moeten worden. Ook is het in sommige RDBMS-en
mogelijk om DISTINCT te gebruiken zodat het gemiddelde van alle verschillende waarden
berekend wordt. (AVG(DISTINCT(GETAL)) bij de waarden 1,1,1 en 3 levert dan 2 op in plaats
van 1,5.)
SUM
De SUM functie totaliseert een numerieke kolom
SELECT WOONPLAATS,SUM(SAL)
FROM WERKNEMERS
GROUP BY WOONPLAATS
levert per WOONPLAATS het totaal aan salarissen op.
Hoofdstuk: Het werken met Gegevens (DML)
AVG
De functie AVG wordt gebruikt om het gemiddelde (AVERAGE) van een bepaalde groepte
berekenen. Zo zouden we het gemiddelde salaris per woonplaats op kunnen vragen door
3
8
Database SQL
1 mei 2010
MAX en MIN
De MAX en de MIN functie berekenen respectievelijk de hoogste en de laagste waarde binnen
een groep.
SELECT WOONPLAATS,MAX(SAL)
FROM WERKNEMERS
GROUP BY WOONPLAATS
geeft ons per woonplaats het hoogste salaris, terwijl
SELECT WOONPLAATS,MIN(SAL)
FROM WERKNEMERS
GROUP BY WOONPLAATS
ons het laagste salaris per woonplaats oplevert.
Het is ook toegestaan om te groeperen op meerdere kolommen. Als we bijvoorbeeld een
overzicht willen hebben van het aantal werknemers per woonplaats en binnen woonplaats per
postcode gebied kunnen we opvragen
SELECT WOONPLAATS,POSTCODE,COUNT(*)
FROM WERKNEMERS
GROUP BY WOONPLAATS,POSTCODE
De GROUP FUNCTIES kunnen ook gebruikt worden zonder het GROUP BY gedeelte. Dat komt
met name van pas als we zo’n functie willen gebruiken voor een hele tabel. We beschouwen
dan in feite de gehele tabel als een groep.
De opdracht
geeft ons een overzicht van achtereenvolgens het aantal rijen, het gemiddelde salaris, het
totaalbedrag van alle salarissen, het hoogste salaris en het laagste salaris van alle werknemers
in de WERKNEMERS tabel.
Aan gegroepeerde rijen kunnen we ook typische groepsvoorwaarden' stellen. Zo zouden we
bijvoorbeeld het aantal werknemers per woonplaats op kunnen vragen maar daar tegelijkertijd
aan toe kunnen voegen dat we in het overzicht alleen die woonplaatsen willen zien die meer
dan 5 werknemers hebben.
Hoofdstuk: Het werken met Gegevens (DML)
SELECT COUNT(*), AVG(SAL), SUM(SAL), MAX(SAL), MIN(SAL)
FROM WERKNEMERS
3
9
Database SQL
1 mei 2010
HAVING
Dan moeten we gebruik maken van HAVING.
SELECT WOONPLAATS,COUNT(*)
FROM WERKNEMERS
GROUP BY WOONPLAATS
HAVING COUNT(*) > 5
Dat geeft dan het volgende resultaat
WOONPLAATS
AMSTERDAM
ROTTERDAM
COUNT(*)
6
7
Het RDBMS zal nog steeds de eerste stappen uit de eerder genoemde opdracht zonder
HAVING uitvoeren, maar zal voordat het resultaat op het scherm wordt afgedrukt als het ware
nog die groepen uitfilteren die niet aan de, in het HAVING gedeelte gestelde, voorwaarde
voldoen.
Uiteraard is het toegestaan om in een SELECT opdracht met een GROUP BY voorwaarden te
stellen met behulp van een WHERE gedeelte. We moeten ons dan goed realiseren dat het
WHERE gedeelte eerder wordt uitgevoerd dan het GROUP BY gedeelte, zodat er groepen
gemaakt worden van alleen die rijen die aan de, in het WHERE gedeelte gestelde, voorwaarde
voldoen.
SELECT WOONPLAATS,AVG(SAL)
FROM WERKNEMERS
WHERE SAL>2500
GROUP BY WOONPLAATS
Apart aandacht verdient nog de waarde NULL oftewel de niet ingevulde waarde. Bedenk dat er
dus ook een groep kan ontstaan van records waarbij in de kolom die we in het GROUP BY
gedeelte gebruiken, niets is ingevuld.
Hoofdstuk: Het werken met Gegevens (DML)
Geeft ons per woonplaats het gemiddelde salaris van iedereen die meer dan 2500 Euro
verdient.
4
0
Database SQL
1 mei 2010
OPDRACHTEN
Geef een opdracht in SQL voor het opvragen van de volgende overzichten uit de WERKNEMERS
tabel
Hoofdstuk: Het werken met Gegevens (DML)
1. Per woonplaats het gemiddelde salaris.
2. Het hoogste salaris dat per chef door een ondergeschikte verdiend wordt.
3. Idem als vraag 2 maar nu tellen alleen de werknemers die minder dan 4000 Euro
verdienen mee.
4. Het aantal werknemers dat onder iedere chef valt, chefs met minder dan twee
ondergeschikten moeten niet vermeld worden
5. Die woonplaatsen waar het gemiddelde salaris hoger is dan 2600 Euro.
4
1
Database SQL
1 mei 2010
HET RAADPLEGEN VAN MEERDERE TABELLEN
De verschillende mogelijkheden
Voor het raadplegen van gegevens uit meerdere tabellen hebben we de beschikking over een
aantal mogelijkheden. In de eerste plaats kunnen we natuurlijk gebruik maken van de eerder
besproken JOIN.
Naast de JOIN kennen we de SUBQUERY, die ook gebruikt kan worden voor het raadplegen van
gegevens uit één tabel maar eigenlijk het best tot zijn recht komt bij het gebruik van meerdere
tabellen. Bovendien zullen we zien dat we in veel gevallen zowel een JOIN als een SUBQUERY
kunnen gebruiken om een antwoord te vinden op een bepaalde vraag.
Tenslotte hebben we dan ook de UNION, MINUS EN INTERSECT mogelijkheden. Met deze
opdrachten doen we eigenlijk niets anders dan het bewerken van de resultaten van twee
SELECT opdrachten. We zullen in paragraaf 4.4 stilstaan bij deze opdrachten.
Voordat we deze verschillende mogelijkheden gaan bespreken zullen we nog een drietal
tabellen aan onze database gaan toevoegen. We zullen volstaan met het geven van de CREATE
opdrachten waarmee deze tabellen gemaakt zijn en een overzicht geven van de ingevulde
waarden.
Om te beginnen maken we een tabel PROJECTEN aan. Deze tabel is, in een enigszins verkorte
vorm, bij het normaliseren al eens aan de orde geweest.
Indien de data dictionaire hiertoe geen mogelijkheden biedt, kunnen we de sleutel kolom
beschermen door
CREATE UNIQUE INDEX PROJ_PROJ_CODE ON PROJECTEN(PROJ_CODE)
De volgende waarden zijn ingevuld:
PROJ_CODE
110
120
130
140
150
PROJ_NAAM
ITCZ
MTS
CAIA
GABD
ZVH
PROJ_PLAATS
ROTTERDAM
ROTTERDAM
AMSTERDAM
UTRECHT
MAASTRICHT
PROJ_LEIDER
40
10
30
60
35
START_DATUM
01-JAN-95
15-AUG-95
01-OCT-96
01-JAN-96
15-FEB-96
BUDGET
100.000
145.000
80.000
98.000
112.000
Vervolgens maken we een tabel WERK aan die de gegevens over de werkzaamheden van de
verschillende werknemers aan de verschillende projecten vastlegt. Deze tabel brengt dus een
verband aan tussen de tabel WERKNEMERS en de tabel PROJECTEN.
CREATE TABLE WERK (
PROJ_CODE CHAR(3) NOT NULL,
CODE CHAR(3) NOT NULL,
UREN NUMBER(4)
)
Hoofdstuk: HET RAADPLEGEN VAN MEERDERE TABELLEN
CREATE TABLE PROJECTEN (
PROJ_CODE CHAR(3) NOT NULL,
PROJ_NAAM CHAR(15) NOT NULL,
PROJ_PLAATS CHAR(20),
PROJ_LEIDER CHAR(3),
STARTDATUM DATE,
BUDGET NUMBER(6)
)
4
2
Database SQL
1 mei 2010
Ook hier kunnen we de (samengestelde) sleutel beschermen met
CREATE UNIQUE INDEX WERK_PRJODE ON WERK(PROLCODE,CODE)
Ingevuld zijn de volgende waarden
PROJ_CODE
110
110
110
110
110
120
120
120
120
120
120
130
130
140
140
140
150
150
150
150
CODE
40
25
45
26
10
10
50
20
12
26
40
30
26
60
48
26
35
47
28
26
UREN
120
48
90
28
12
80
76
18
63
18
38
26
70
50
81
26
90
22
10
18
CREATE TABLE SCHALEN (
SCHAAL CHAR(2) NOT NULL,
LAAGSTE NUMBER(8,2),
HOOGSTE NUMBER(8,2)
)
Vervolgens eventueel
CREATE UNIQUE INDEX SCHALEN_SCH ON SCHALEN(SCHAAL)
Ingevuld geeft dat
SCHAAL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
LAAGSTE
1600,00
2000,00
2300,00
2600,00
2900,00
3200,00
3500,00
3800,00
4100,00
4500,00
5000,00
5500,00
6000,00
6500,00
HOOGSTE
1999,99
2299,99
2599,99
2899,99
3199,99
3499,99
3799,99
4099,99
4499,99
4999,99
5499,99
5999,99
6499,99
9999,99
Hoofdstuk: HET RAADPLEGEN VAN MEERDERE TABELLEN
Tenslotte maken we nog een tabel aan waarin we vastleggen welke SALARISSCHALEN er in
onze organisatie zijn. We leggen uiteraard het nummer van de schaal en de hoogste en laagste
salarissen binnen iedere schaal vast.
4
3
Database SQL
1 mei 2010
De JOIN
Zoals we in paragraaf 3.2 al hebben kunnen zien is het mogelijk om gegevens uit meerdere
tabellen te raadplegen door gebruik te maken van de JOIN. Dat wil zeggen dat we achter het
FROM gedeelte meerdere tabellen noemen en vervolgens (om het cartesiaans produkt te
beperken) in het WHERE gedeelte nadere voorwaarden stellen. De meest voor de hand
liggende en daardoor ook meest gebruikte vorm is die waarbij we stellen dat alle kolommen in
alle rijen van het cartesiaans produkt betrekking hebben op dezelfde entiteit. Dit kunnen we
doen door te stellen dat de inhoud van twee kolommen die in beide tabellen voorkomen, gelijk
moeten zijn aan elkaar. We noemen dit ook wel de EQUIJOIN vanwege het = teken dat gebruikt wordt.
Als we dit willen doen, moeten we er uiteraard voor zorgen dat er in beide tabellen een
overeenkomstige kolom voorkomt. Als er een goede gegevensanalyse en een goede
normalisatie (zie DEEL 1) heeft plaatsgevonden is dat ook het geval.
Als we nu bijvoorbeeld gegevens op willen vragen uit de tabellen WERKNEMERS en WERK,
laten we zeggen de CODE van de werknemers, hun NAAM en de PROJJODE met het aantal
UREN dat de werknemer aan dat project heeft gewerkt gebruiken we
SELECT WERKNEMERS.CODE,NAAM,PROJ_CODE,UREN
FROM WERKNEMERS,WERK
WHERE WERKNEMERS.CODE = WERK.CODE
We moeten weer rekening houden met het feit dat de kolom CODE zowel in WERKNEMERS als
in WERK voorkomt dus moeten we aangeven welke CODE kolom we bedoelen. In het
bovenstaande voorbeeld is het uiteraard net zo goed mogelijk om te vragen WERK.CODE af te
drukken in plaats van WERKNEMERS.CODE. Het zal ook duidelijk zijn dat een werknemer die
aan meerdere projecten werkt nu ook meerdere malen in ons overzicht voor zal komen. Zijn of
haar CODE is immers een aantal malen gelijk aan een CODE in de tabel WERK.
We hadden natuurlijk ook op kunnen geven
SELECT WERKNEMERS.CODE,WERKNEMERS.NAAM,
WERK. PROJ_ CODE, WERK. UREN
FROM WERKNEMERS,WERK
WHERE WERKNEMERS.CODE = WERK.CODE
maar omdat de kolommen NAAM,PROJ_CODE en UREN niet in beide tabellen voorkomen en er
dus geen verwarring mogelijk is, laten we de tabelaanduiding meestal achterwege.
Hoofdstuk: HET RAADPLEGEN VAN MEERDERE TABELLEN
In onze database is er een verband aan te brengen tussen de tabel WERKNEMERS en de tabel
WERK doordat in beide tabellen de kolom CODE voorkomt. Bovendien kunnen we een verband
aanbrengen tussen de tabellen PROJECTEN en WERK door middel van de kolom PROJ_CODE.
Uiteraard is het dan ook mogelijk om een verband aan te brengen tussen WERKNEMERS en
PROJECTEN via de tabel WERK. Schematisch hebben we dus de volgende situatie
4
4
Database SQL
1 mei 2010
Het is uiteraard ook mogelijk om een JOIN te maken van meer dan twee tabellen. We zouden
de voorgaande vraag kunnen uitbreiden door ook de PROJ_NAAM in onze vraagstelling op te
nemen. We krijgen dan:
SELECT WERKNEMERS.CODE, NAAM,
PROJECTEN. PROJ_CODE, PROJ_NAAM,UREN
FROM WERKNEMERS,WERK,PROJECTEN
WHERE WERKNEMERS.CODE = WERK.CODE AND
WERK.PROJ_CODE = PROJECTEN.PROJ_CODE
Om dit geheel wat in te korten (en omdat we deze mogelijkheid in het vervolg nog nodig
hebben) kunnen we gebruik maken van zogenaamde ALIAS namen voor de tabellen. Dat geven
we aan door na de naam van de tabel in het FROM gedeelte een spatie en vervolgens de
alternatieve naam op te geven. Zo zouden we de vorige opdracht ook hebben kunnen
formuleren als
Hoofdstuk: HET RAADPLEGEN VAN MEERDERE TABELLEN
SELECT A.CODE, NAAM, C.PROJ_CODE,
PROJ_NAAM, UREN
FROM WERKNEMERS A,WERK B,PROJECTEN C
WHERE A.CODE = B.CODE AND B.PROJ_CODE = C.PROJ_CODE
4
5
Database SQL
1 mei 2010
OPDRACHTEN
Geef een opdracht in SQL voor het opvragen van de volgende overzichten uit de
WERKNEMERS, WERK, PROJECTEN en SCHALEN tabellen
1.De codes, namen (van de werknemers) en de projectcodes van de projecten waar de
werknemers aan werken.
2.De projectcodes, projectnamen en medewerkerscodes van alle projecten.
3.De codes, namen, projectcodes, projectnamen en de bestede uren per werknemer.
4. De namen en de bestede uren van alle werknemers.
5. De namen en de bestede uren van alle werknemers uit UTRECHT.
6.De projectnamen van alle projecten waar werknemers die in ROTTERDAM wonen aan
meewerken.
Hoofdstuk: HET RAADPLEGEN VAN MEERDERE TABELLEN
7.De namen van alle werknemers die aan een project in AMSTERDAM werken.
4
6
Database SQL
1 mei 2010
De OUTERJOIN
In sommige gevallen komt het voor dat we een overzicht willen hebben van gegevens uit
meerdere kolommen en daarbij ook gegevens willen zien van entiteiten die niet in beide
tabellen voorkomen.
Als we naar het voorbeeld uit de vorige paragraaf kijken zien we dat de werknemers die niet
aan een project werken en wiens CODE dus niet voorkomt in de tabel WERK niet afgebeeld
worden in ons overzicht. Hun CODE is immers in geen enkel geval gelijk aan een CODE uit de
WERK tabel! Als we deze werknemers toch in ons overzicht willen betrekken, is daar in de
standaard SQL opdrachten geen mogelijkheid voor. Sommige RDBMS’en zoals ORACLE geven
ons die mogelijkheid wel door de zogenaamde OUTERJOIN.
De OUTERJOIN is een vorm van de EQUIJOIN waarbij we als het ware zeggen: 'Als het zo is dat
een kolomwaarde die in één van de twee tabellen voorkomt (en gebruikt wordt in het WHERE
gedeelte) niet voorkomt in de andere tabel, neem deze rij dan toch éénmalig op in het
uiteindelijke overzicht'
We geven dit aan door in het WHERE gedeelte, na de naam van de kolom waar de waarde
eventueel niet in voorkomt, een tussen haakjes geplaatst + teken te zetten.
De vraag uit de vorige paragraaf zou er dan als volgt uit komen te zien
SELECT WERKNEMERS.CODE,NAAM,
PROJECTEN.PROJ_CODE, PROJ_NAAM,UREN
FROM WERKNEMERS,WERK,PROJECTEN
WHERE WERKNEMERS.CODE = WERK.CODE(+) AND WERK.PROJ_CODE =
PROJECTEN.PROJ_CODE(+)
De AUTOJOIN
Er is een aantal vragen dat ook met de tot nu toe behandelde mogelijkheden niet op te lossen
is. Dat geldt met name voor vragen waarbij we eigenlijk voorwaarden willen stellen die
betrekking hebben op dezelfde tabel als waar we gegevens uit raadplegen.
Dat is bijvoorbeeld het geval bij een vraag als: Welke werknemers hebben een hoger salaris
dan hun chef? We willen dan eigenlijk de werknemers koppelen aan hun chef om te kunnen
testen of hun salaris hoger is dan het salaris van die chef. Dat zou geen problemen opleveren
als we een aparte CHEFS tabel tot onze beschikking zouden hebben. We zouden dan immers de
volgende situatie hebben:
WERKNEMERS
CODE NAAM
SAL
10
JAN
100
20
30
40
50
IRENE
KAREL
INGE
PETER
80
90
110
60
CHEF
CHEFS
CODE
SAL
20
20
80
30
90
30
30
Hoofdstuk: HET RAADPLEGEN VAN MEERDERE TABELLEN
Hierdoor worden dus ook de werknemers die niet aan een project werken in ons overzicht
opgenomen. Bij de kolommen PROJ_CODE, PROJ_NAAM en UREN wordt dan de waarde NULL
in ons overzicht geplaatst.
4
7
Database SQL
1 mei 2010
Als we dan willen weten welke werknemer meer verdient dan zijn of haar chef vragen we
eenvoudigweg
SELECT NAAM
FROM WERKNEMERS,CHEFS
WHERE WERKNEMERS.CHEF=CHEFS.CODE AND WERKNEMERS.SAL>C HEFS.SAL
De JOIN van de tabellen WERKNEMERS en CHEFS levert het volgende tussenresultaat op (we
koppelen alle rijen uit de twee tabellen waarvoor geldt dat de waarde ingevuld bij de kolom
CHEF in de WERKNEMERS tabel gelijk is aan de waarde in de kolom CODE in de CHEFS tabel, en
hebben dus de werknemers en hun chefs aan elkaar gekoppeld)
CODE
10
40
50
NAAM
JAN
INGE
PETER
SAL
100
110
60
CHEF
20
30
30
CODE
20
30
30
SAL
80
90
90
CODE
20
30
SAL
80
90
Hier wordt dan vervolgens de voorwaarde
WERKNEMERS. SAL>CHEFS.SAL
op toegepast. Dat levert het volgende tussenresultaat op
CODE
10
40
NAAM
JAN
INGE
SAL
100
110
CHEF
20
30
Tenslotte volgt er dan nog de, inmiddels welbekende, PROJECTIE en dat geeft als eindresultaat
JAN
INGE
Maar helaas heeft het proces van normalisatie er toe geleid dat er geen aparte tabel CHEFS is.
Dat zorgt er voor dat er zo weinig mogelijk gegevens dubbel (dus redundant) worden
opgeslagen maar maakt de vraagstelling er niet gemakkelijker op.
We kunnen dit probleem oplossen door gebruik te maken van de mogelijkheid om een tabel
twee ALIAS namen te geven en die tabellen vervolgens gewoon als twee aparte tabellen te behandelen.
Vervolgens doen we precies hetzelfde als in het voorgaande geval; we koppelen de
werknemers aan hun chefs, controleren of hun salaris hoger is dan dat van die chef en laten
van alle werknemers waar dit voor geldt hun naam afdrukken
SELECT WERKERS.NAAM
FROM WERKNEMERS WERKERS,
WERKNEMERS CHEFS
WHERE WERKERS.CHEF = CHEFS.CODE AND
WERKERS.SAL > CHEFS.SAL
Hoofdstuk: HET RAADPLEGEN VAN MEERDERE TABELLEN
NAAM
4
8
Database SQL
1 mei 2010
Omdat de kolom NAAM in beide tabellen voorkomt moeten we weer aangeven welke kolom
we bedoelen. In dit geval is het natuurlijk wel van belang welke van de twee we kiezen!
Dit levert ons dan het volgende overzicht op
NAAM
JANSMA
PAREE
ZEEUW
OPDRACHTEN
Geef een opdracht in SQL voor het opvragen van de volgende overzichten uit de
WERKNEMERS, WERK, PROJECTEN en SCHALEN tabellen
1. De namen van alle werknemers,die meer verdienen dan iemand anders die in dezelfde
woonplaats woont als zij zelf.
2. De namen van alle projecten die een budget hebben dat hoger is dan het budget van een
project dat in dezelfde projectplaats wordt uitgevoerd.
3. De namen van alle werknemers die meer verdienen dan werknemer PAREE.
4. De namen van alle werknemers die meer verdienen dan een werknemer die voor dezelfde
chef werkt.
Hoofdstuk: HET RAADPLEGEN VAN MEERDERE TABELLEN
5. De namen van alle werknemers die eerder in dienst gekomen zijn dan hun chef.
4
9
Database SQL
1 mei 2010
De NON-EQUIJOIN
In de vorige paragraaf hebben we eigenlijk al kunnen zien dat de voorwaarden in het WHERE
gedeelte bij de JOIN niet beperkt hoeven te blijven tot gelijkstellende voorwaarden (de
EQUIJOIN) maar dat we ook < , > en andere operatoren mogen gebruiken. Zo’n JOIN noemen
we dan ook een NON-EQUIJOIN.
Het is zelfs toegestaan om bijvoorbeeld de BETWEEN operator te gebruiken. Dit zouden we in
onze database toe kunnen passen door te vragen naar de namen van de werknemers met
daarbij afgedrukt hun salaris en hun salarisschaal. We moeten dan een JOIN formuleren van de
WERKNEMERS tabel met de SCHALEN tabel. De SCHAAL die we dan willen koppelen aan de
rijen uit de WERKNEMERS tabel betreft dan steeds die schaal die een boven- en een
ondergrens kent waartussen het salaris van de desbetreffende werknemer zich bevindt. We
kunnen dat als volgt bereiken:
SELECT NAAM,SAL,SCHAAL
FROM WERKNEMERS,SCHALEN
WHERE SAL BETWEEN LAAGSTE AND HOOGSTE
De SUBQUERY
Naast het gebruik van de JOIN om gegevens uit meerdere tabellen te raadplegen kennen we de
SUBQUERY oftewel de sub-vraag om bepaalde problemen op te lossen. Er is vrijwel geen enkel
probleem te bedenken dat we niet ook met de JOIN op zouden kunnen lossen maar in veel
gevallen is de SUBQUERY een stuk helderder en bovendien eenvoudiger te formuleren.
SELECT WOONPLAATS
FROM WERKNEMERS
WHERE NAAM = 'BOS'
Met als resultaat
WOONPLAATS
ROTTERDAM
en vervolgens
SELECT NAAM
FROM WERKNEMERS
WHERE WOONPLAATS = 'ROTTERDAM'
Uiteraard levert dit het antwoord op onze vraag op, maar het zou zoveel eenvoudiger zijn als
we dat in één stap zouden kunnen doen. Laten we het eerst eens op gaan lossen met een JOIN
SELECT WERKERS1.NAAM
FROM WERKNEMERS WERKERS1,WERKNEMERS WERKERS2
WHERE WERKERS2.NAAM = 'BOS' AND
WERKERS1.WOONPLAATS = WERKERS2WOONPLAATS
Hoofdstuk: HET RAADPLEGEN VAN MEERDERE TABELLEN
Stel dat we op zoek zijn naar de namen van alle werknemers die in dezelfde plaats wonen als
werknemer BOS. Natuurlijk kunnen we het antwoord hierop in twee stappen verkrijgen:
5
0
Database SQL
1 mei 2010
Daarmee koppelen we iedere rij uit de WERKNEMERS tabel (die we WERKERS1 noemen) met
iedere rij uit nogmaals de WERKNEMERS tabel (nu WERKERS2 genoemd) als geldt dat in het
tweede gedeelte bij NAAM (WERKERS2.NAAM dus) 'BOS' is ingevuld en als bovendien de
WOONPLAATS in beide gedeelten (WERKERS1 en WERKERS2) hetzelfde is.
Alleen al het feit dat hier enige uitleg nodig is bij de oplossing van een vrij eenvoudige vraag,
geeft aan dat de wijze van oplossen niet erg simpel is. Met een SUBQUERY is het eigenlijk veel
eenvoudiger op te lossen
SELECT NAAM
FROM WERKNEMERS
WHERE WOONPLAATS = (
SELECT WOONPLAATS
FROM WERKNEMERS
WHERE NAAM = 'BOS'
)
Als we deze oplossing zien, zien we al vrij snel wat de bedoeling is, namelijk 'Geef de namen
van alle werknemers met als woonplaats (de woonplaats van BOS)'. Dit is niet alleen wat
sneller te doorzien maar sluit ook meer aan bij de wijze waarop we de vraag geformuleerd
hadden.
Door gebruik te maken van een sub-vraag kunnen we eigenlijk op vrij eenvoudige wijze
vraagstellingen zoals in het voorgaande oplossen.
zal dit tot een foutmelding leiden omdat de SUBQUERY hier meerdere woonplaatsen oplevert
en geen enkele waarde uit een rij kan gelijk zijn aan de waarden uit meerdere andere rijen. We
gebruiken dan de (al eerder behandelde) IN operator.
Dus
SELECT NAAM
FROM WERKNEMERS
WHERE WOONPLAATS IN
(
SELECT WOONPLAATS
FROM WERKNEMERS
WHERE CHEF = '40'
)
Het is ook mogelijk om meerdere SUBQUERIES aan elkaar te koppelen.
De voorgaande vraag zouden we ook kunnen formuleren als:
Welke werknemers wonen in dezelfde plaats als de werknemers die als chef MERK hebben?
Hoofdstuk: HET RAADPLEGEN VAN MEERDERE TABELLEN
SELECT NAAM
FROM WERKNEMERS
WHERE WOONPLAATS =(
SELECT WOONPLAATS
FROM WERKNEMERS
WHERE CHEF = '40'
)
5
1
Database SQL
1 mei 2010
Dat lossen we op door :
OPDRACHTEN
Geef een opdracht in SQL voor het opvragen van de volgende overzichten uit de
WERKNEMERS, WERK, PROJECTEN en SCHALEN tabellen
1. De namen van werknemers die dezelfde chef hebben als werknemer 40.
2. De namen van werknemers die aan hetzelfde project werken als werknemer 35.
3. De namen van projecten die uitgevoerd worden In dezelfde plaats als de woonplaats
van werknemer BOS.
4. De namen van werknemers die in een andere plaats wonen dan werknemer 99.
5. De namen van werknemers die een hoger salaris hebben dan werknemer 12.
6. De namen van projecten waar werknemer MERK aan werkt.
7. De woonplaatsen van werknemers die aan hetzelfde project werken als werknemer
MERK.
8. De namen van alle werknemers die in dezelfde salarisschaal vallen als werknemer BOS.
9. De projectcodes van alle projecten waar een werknemer meer dan 30 uur aan gewerkt
heeft.
10. De namen van werknemers die dezelfde chef hebben als werknemer MAAS en in
dezelfde plaats wonen als werknemer PAREE.
Hoofdstuk: HET RAADPLEGEN VAN MEERDERE TABELLEN
SELECT NAAM
FROM WERKNEMERS
WHERE WOONPLAATS IN
(
SELECT WOONPLAATS
FROM WERKNEMERS
WHERE CHEF IN
(
SELECT CODE
FROM WERKNEMERS
WHERE NAAM = 'MERK'
)
)
5
2
Database SQL
1 mei 2010
ANY en ALL
Speciaal voor gebruik met SUBQUERIES zijn de operatoren ANY en ALL beschikbaar. Hoewel ze
in veel gevallen overbodig zijn en vaak vervangen kunnen worden door de (nog te behandelen)
EXISTS operator, kunnen in sommige gevallen de ANY en ALL operatoren goede diensten
bewijzen.
Als we ons bijvoorbeeld afvragen welke werknemers er meer verdienen dan alle werknemers
uit ROTTERDAM kunnen we daarvoor de ALL operator in combinatie met de > operator
gebruiken
SELECT NAAM
FROM WERKNEMERS
WHERE SAL > ALL (
SELECT SAL
FROM WERKNEMERS
WHERE WOONPLAATS = 'ROTTERDAM'
)
De ANY operator geeft dus aan, dat het voldoen aan één enkele waarde in de SUBQUERY
genoeg is.
Uiteraard zijn ANY en ALL ook te gebruiken in combinatie met de operatoren >= < en <=
Het gebruik van de ANY en ALL operatoren in combinatie met = en ! = is wel toegestaan maar
niet aan te raden omdat het vaak leidt tot ondoorzichtig geformuleerde vraagstellingen.
Bovendien kan dit altijd vermeden worden door gebruik te maken van IN en NOT IN.
OPDRACHTEN
Geef een opdracht in SQL voor het opvragen van de volgende overzichten uit de
WERKNEMERS, WERK, PROJECTEN en SCHALEN tabellen
1. De namen van werknemers die later in dienst zijn gekomen dan alle werknemers uit
ROTTERDAM.
2. De namen van werknemers die eerder in dienst zijn gekomen dan een werknemer uit
AMSTERDAM.
3. De namen van projecten die een "groter budget hebben dan alle projecten waar
werknemer 4Q aan werkt.
Hoofdstuk: HET RAADPLEGEN VAN MEERDERE TABELLEN
Het gebruik van de ALL operator houdt dus in dat het salaris in alle gevallen groter moet zijn
dan de salarissen van werknemers uit ROTTERDAM.
Vinden we het daarentegen voldoende als de werknemer een salaris heeft dat hoger is dan dat
van een willekeurige werknemer uit ROTTERDAM, dan kunnen we ANY gebruiken
SELECT NAAM
FROM WERKNEMERS
WHERE SAL > ANY (
SELECT SAL
FROM WERKNEMERS
WHERE WOONPLAATS = 'ROTTERDAM'
)
5
3
Hoofdstuk: HET RAADPLEGEN VAN MEERDERE TABELLEN
Database SQL
1 mei 2010
5
4
Database SQL
1 mei 2010
De gesynchroniseerde SUBQUERY
Tot nu toe hebben we het uitsluitend gehad over SUBQUERIES die onafhankelijk van de
hoofdquery werden uitgevoerd. Met andere woorden, er werd eerst een soort deelverzameling
van rijen geselecteerd door middel van een SELECT instructie tussen haakjes om vervolgens de
te selecteren rijen te toetsen aan deze verzameling. De samengestelde deelverzameling was
dus een statisch geheel waaraan de te selecteren rijen getoetst werden.
Het is echter ook mogelijk om de SUBQUERY te koppelen aan de HOOFDQUERY. We kunnen
dus voor iedere rij die beoordeeld wordt, opnieuw de deelverzameling waaraan getoetst wordt
samen laten stellen. Hierdoor krijgt de subquery een veel dynamischer karakter en loopt dus
.eigenlijk synchroon met de hoofdquery, vandaar ook de benaming gesynchroniseerde
subquery (soms ook wel gecorreleerde subquery genoemd vanwege het verband (de
correlatie) met de hoofdquery).
In zijn kernvorm ziet de gesynchroniseerde SUBQUERY er als volgt uit
We hebben een dergelijke constructie bijvoorbeeld nodig als we op zoek zijn naar alle
werknemers met een hoger salaris dan het gemiddelde salaris van de werknemers uit hun
WOONPLAATS. We hebben dan immers behoefte aan een steeds veranderend gemiddelde
salaris namelijk het gemiddelde salaris van de werknemers uit de WOONPLAATS van de
werknemer die op dat moment voor selectie in aanmerking komt. Een steeds weer opnieuw te
berekenen, dynamisch oftewel gesynchroniseerd gemiddelde! We lossen dit probleem als volgt
op
SELECT NAAM
FROM WERKNEMERS W WHERE SAL >
(
SELECT AVG(SAL)
FROM WERKNEMERS
WHERE WOONPLAATS = W.WOONPLAATS
)
Met behulp van een dergelijke constructie zouden we dus ook de vraag kunnen beantwoorden
welke werknemer PER WOONPLAATS het hoogste salaris heeft
SELECT NAAM
FROM WERKNEMERS W
WHERE SAL = (
SELECT MAX(SAL)
FROM WERKNEMERS
WHERE WOONPLAATS = W.WOONPLAATS
Hoofdstuk: HET RAADPLEGEN VAN MEERDERE TABELLEN
SELECT <kolom naam>
FROM <tabel naam 1 > <aliasnaam>
WHERE <voorwaarde>
(
SELECT <kolomnaam>
FROM <tabelnaam2>
WHERE <uitdrukking> <operator> <aliasnaam
.kolomnaam>
)
5
5
Database SQL
1 mei 2010
)
De EXISTS operator
De EXISTS operator wordt gebruikt om te testen of een rij wel of niet voorkomt in een bepaalde
tabel. Hoewel de EXISTS operator slechts in enkele gevallen noodzakelijk is, zullen we hem hier
toch behandelen. In sommige RDBMS-en is het niet toegestaan om een GROUP FUNCTIE aan
beide zijden van een operator te gebruiken. In deze gevallen moeten we de EXISTS operator
gebruiken.
We zouden ons bijvoorbeeld af kunnen vragen welke werknemers tenminste één of meer
werknemers 'onder zich hebben' in de hiërarchie van de organisatie. We zouden dat als volgt
op kunnen lossen :
SELECT NAAM
FROM WERKNEMERS W
WHERE EXISTS (
SELECT *
FROM WERKNEMERS
WHERE CHEF = W.CODE
)
Hierbij vragen we ons dus steeds af: 'Bestaat er een rij in de WERKNEMERS tabel waarvoor
geldt dat er in de kolom CHEF een waarde is ingevuld die gelijk is aan de waarde die ingevuld is
in de kolom CODE van de rij die op het punt staat geselecteerd te worden? Is dat het geval druk
dan de waarde uit de kolom NAAM van die rij af.'
De oplettende en fantasierijke lezer had natuurlijk al opgemerkt dat dit probleem ook op te
lossen is door middel van een JOIN van de tabel WERKNEMERS met zichzelf (de AUTOJOIN dus)
OPDRACHTEN
Geef een opdracht in SQL voor het opvragen van de volgende overzichten uit de
WERKNEMERS, WERK, PROJECTEN en SCHALEN tabellen
1. De namen van alle werknemers die tenminste aan alle projecten werken waar ook
werknemer 40 aan werkt. (Gebruik de EXISTS operator!)
Hoofdstuk: HET RAADPLEGEN VAN MEERDERE TABELLEN
SELECT DISTINCT CHEFS.NAAM
FROM WERKNEMERS WERKERS,WERKNEMERS CHEFS
WHERE WERKERS.CHEF=CHEFS.CODE
5
6
Database SQL
1 mei 2010
UNION, MINUS en INTERSECT
De UNION, MINUS en INTERSECT operatoren voeren bewerkingen uit op tabellen die het
resultaat zijn van twee SELECT opdrachten. Deze resultaat tabellen kunnen we beschouwen als
verzamelingen van elementen. Als we uitgaan van twee verzamelingen A en B, zal de UNION de
optelsom van alle elementen van verzameling A en B opleveren. De MINUS geeft bij A - B alle
elementen van A behalve die elementen die ook onderdeel uitmaken van B en B - A levert alle
elementen van verzameling B op behalve die elementen die ook lid zijn van A. De INTERSECT
tenslotte zal alle elementen die voorkomen bij A en ook onderdeel uitmaken van B
presenteren. We kunnen dit grafisch duidelijk weergeven:
SELECT NAAM,TELEFOON
FROM WERKNEMERS
WHERE WOONPLAATS = 'AMSTERDAM'
UNION
SELECT NAAM,TELEFOON
FROM WERKNEMERS
WHERE WOONPLAATS = 'UTRECHT'
Deze vraag is natuurlijk gemakkelijker te beantwoorden door gebruik te maken van OR
SELECT NAAM,TELEFOON
FROM WERKNEMERS
WHERE WOONPLAATS = 'AMSTERDAM' OR WOONPLAATS = 'UTRECHT'
Of met de IN operator
SELECT NAAM,TELEFOON FROM WERKNEMERS
WHERE WOONPLAATS IN ('AMSTERDAM':UTRECHT')
We kunnen echter niet in alle gevallen gebruik maken van IN of OR.
Hoofdstuk: HET RAADPLEGEN VAN MEERDERE TABELLEN
Omdat we hierbij de resultaat tabellen als verzamelingen beschouwen, zullen ook de eventueel
dubbel voorkomende rijen buiten beschouwing worden gelaten. Het gebruik van DISTINCT bij
deze operatoren is dus overbodig.
De UNION operator doet dus eigenlijk niets anders dan twee of meer resultaattabellen bij
elkaar tellen. Het spreekt voor zich dat, dat betekent dat het aantal kolommen en het type van
de kolommen uit de resultaattabellen met elkaar moeten overeenkomen.
We zouden bijvoorbeeld de namen en telefoonnummers van alle werknemers uit AMSTERDAM
of UTRECHT in een tabel kunnen zetten met
5
7
Database SQL
1 mei 2010
Stel dat we, naast de WERKNEMERS tabel, ook de beschikking hebben over een tabel met
gepensioneerde werknemers en we willen een overzicht in een resultaattabel van alle
werknemers en gepensioneerden uit AMSTERDAM of UTRECHT.
Bij dit soort vragen kan de UNION operator goede diensten bewijzen
SELECT NAAM,TELEFOON
FROM WERKNEMERS
WHERE WOONPLAATS IN ('AMSTERDAM':UTRECHT')
UNION
SELECT NAAM,TELEFOON
FROM GEPENSIONEERDEN
WHERE WOONPLAATS IN ('AMSTERDAM':UTRECHT')
We kunnen MINUS bijvoorbeeld gebruiken om de vraag te beantwoorden: in welke plaatsen
wonen wel werknemers maar worden geen projecten uitgevoerd:
SELECT WOONPLAATS
FROM WERKNEMERS
MINUS
SELECT PROJ_PLAATS
FROM PROJECTEN
SELECT WOONPLAATS
FROM WERKNEMERS
WHERE WOONPLAATS NOT IN
(
SELECT PROJ_PLAATS
FROM PROJECTEN
)
En zo kunnen we natuurlijk ook alle plaatsen achterhalen waar zowel werknemers wonen als
projecten worden uitgevoerd door:
SELECT WOONPLAATS
FROM WERKNEMERS
INTERSECT
SELECT PROJ_PLAATS
FROM PROJECTEN
OPDRACHTEN
Geef een opdracht in SQL voor het opvragen van de volgende overzichten uit de
WERKNEMERS, WERK, PROJECTEN en SCHALEN tabellen
1. De namen van alle projecten en de namen van alle werknemers in één tabel
gepresenteerd.
2. De codes van alle werknemers en de codes van alle projecten in één tabel
gepresenteerd.
Hoofdstuk: HET RAADPLEGEN VAN MEERDERE TABELLEN
Uiteraard hadden we die vraag ook kunnen beantwoorden met:
5
8
Database SQL
1 mei 2010
VEEL VOORKOMENDE PROBLEMEN MET DE SELECT OPDRACHT
De denkwijze
In het voorgaande zijn we er eigenlijk steeds van uitgegaan dat SOL op vrij eenvoudige wijze
antwoord kan geven op allerlei soorten vragen.
Toch blijkt in de praktijk dat veel mensen na korte tijd tegen dezelfde soort problemen
aanlopen en pas na zeer veel moeite, of soms zelfs helemaal niet, tot een oplossing komen.
Vaak blijkt dan dat men zich de denkwijze die men binnen SOL moet volgen niet goed eigen
gemaakt heeft. In dit hoofdstuk zullen we een poging wagen om, aan de hand van een aantal
vaak terugkerende problemen, de lezer hier alvast op voor te bereiden.
Nog nooit ...
Een probleem vinden veel mensen, die nog weinig ervaring met SOL hebben, vaak de
vraagstellingen die we aan zouden kunnen geven met de zinsnede 'nog nooit ... .'
Als we echter de mogelijkheden van SOL goed op een rijtje zetten, komen we al vrij snel tot de
conclusie dat we een dergelijke vraag eigenlijk zouden moeten benaderen alsof er staat: 'Wie
komt er niet voor in de groep die .... al eens gedaan/gehad hebben 7'
Dat geldt dus ook voor de voorgaande vraag. Eigenlijk zouden we moeten stellen
'Welke werknemers komen niet voor in de groep werknemers die wel eens aan een project in
UTRECHT hebben gewerkt 7'
En deze vraag is in SOL tamelijk eenvoudig te formuleren
SELECT CODE,NAAM
FROM WERKNEMERS
WHERE CODE NOT IN
(
SELECT CODE
FROM WERK
WHERE PROJ_CODE IN
(
)
Nou ja … tamelijk eenvoudig?!
)
SELECT PROJ_CODE
FROM PROJECTEN
WHERE PROJ_PLAATS = 'UTRECHT'
Hoofdstuk: VEEL VOORKOMENDE PROBLEMEN MET DE SELECT OPDRACHT
Vragen als: 'Welke werknemers hebben nog nooit aan een project in UTRECHT gewerkt 7'
worden dan gezien als onoverkomelijke problemen.
5
9
Database SQL
1 mei 2010
OPDRACHTEN
Geef een opdracht in SQL voor het opvragen van de volgende overzichten uit de
WERKNEMERS, WERK, PROJECTEN en SCHALEN tabellen
1. De namen van werknemers die nog nooit aan een project hebben gewerkt, dat geleid
wordt door werknemer 10.
2. De namen van projecten waar werknemer 60 nog nooit aan gewerkt heeft.
3. De namen van projecten waar nog nooit iemand uit AMSTERDAM aan gewerkt heeft.
4. De namen van alle werknemers die nog nooit aan een project met PROJJODE 120
hebben gewerkt.
5. De namen van werknemers die nog nooit langer dan 30 uur aan een project hebben
gewerkt.
Een ander, steeds terugkerend, probleem vormen vragen die de zinsnede 'alleen maar' met
zich meebrengen.
We zouden bijvoorbeeld de vraag kunnen stellen welke werknemers alleen maar gewerkt
hebben aan projecten in UTRECHT.
Ook hier moeten we ons realiseren dat er voor 'alleen maar' geen operator in SQL bestaat. Wel
kunnen we stellen dat de desbetreffende werknemer blijkbaar aan een project in UTRECHT
moet werken of gewerkt moet hebben en tegelijkertijd niet aan een project uit een andere
plaats mag werken of gewerkt mag hebben. Zo geformuleerd kunnen we de vraag wel in SQL
beantwoorden
SELECT CODE,NAAM
FROM WERKNEMERS
WHERE CODE IN
(
SELECT CODE
FROM WERK
WHERE PROJ_CODE IN
(
SELECT PROJ_CODE
FROM PROJECTEN
WHERE PROJ_PLAATS = 'UTRECHT'
)
)
AND
CODE NOT IN
(
SELECT CODE
FROM WERK
WHERE PROJ_CODE NOT IN
(
SELECT PROJ_CODE
FROM PROJECTEN
WHERE PROJ_PLAATS = 'UTRECHT'
)
)
Hoofdstuk: VEEL VOORKOMENDE PROBLEMEN MET DE SELECT OPDRACHT
Alleen maar ...
6
0
Database SQL
1 mei 2010
Afgezien van de op het eerste gezicht vrij omslachtig aandoende formulering, zal het duidelijk
zijn dat een goede omschrijving van de eigenlijke vraag en, daarmee samenhangend, een juiste
plaatsing van de ontkenning(en) van groot belang is.
We kunnen deze vraag overigens ook oplossen door middel van
Daarmee stellen we in het eerste gedeelte dat de werknemer niet aan projecten in een andere
plaats dan UTRECHT gewerkt mag hebben. In het tweede gedeelte voegen we toe dat de
desbetreffende werknemer wel voor moet komen in de tabel WERK omdat anders ook de
werknemers die aan geen enkel project werken (en dus ook niet aan een project in een andere
plaats dan UTRECHT) in het resultaat worden opgenomen.
OPDRACHTEN
Geef een opdracht in SQL voor het opvragen van de volgende overzichten uit de
WERKNEMERS, WERK, PROJECTEN en SCHALEN tabellen
1. De namen van werknemers die alleen maar aan projecten geleid door werknemer 10
hebben meegewerkt.
2. De namen van projecten waar alleen maar door werknemers uit ROTTERDAM aan is
gewerkt.
3. De namen van werknemers die alleen maar aan projecten hebben meegewerkt waar
ook door werknemer JOBSE aan is gewerkt.
Hoofdstuk: VEEL VOORKOMENDE PROBLEMEN MET DE SELECT OPDRACHT
SELECT NAAM
FROM WERKNEMRERS
WHERE CODE NOT IN
(
SELECT CODE
FROM WERK
WHERE PROLCODE NOT IN
(
SELECT PROJ_CODE
FROM PROJECTEN
WHERE PROJ_PLAATS='UTRECHT'
)
)
AND
CODE IN
(
SELECT CODE
FROM WERK
)
6
1
Database SQL
1 mei 2010
De (dubbele) ontkenning
Ontkennend geformuleerde vraagstellingen willen nog wel eens problemen opleveren. Met
name het verschil tussen het gebruik van NOT en de != operator leidt nogal eens tot
problemen.
Stel dat we willen weten welke werknemers niet aan het project met PROJ_CODE 110 werken.
Sommige mensen formuleren dit in SQL als
SELECT CODE,NAAM
FROM WERKNEMERS
WHERE CODE IN
(
SELECT CODE FROM WERK
WHERE PROJ CODE != '110'
)
Eigenlijk zouden we de vraagstelling eerst in SQL termen moeten vertalen. We zouden dan
kunnen zeggen dat we op zoek zijn naar alle werknemers die niet behoren tot de groep
werknemers die aan project 110 werken. Zo gesteld is de vraag vrij eenvoudig in SQL te
formuleren.
SELECT CODE,NAAM
FROM WERKNEMERS
WHERE CODE NOT IN
(
SELECT CODE
FROM WERK
WHERE PROJ_CODE = '110'
)
De ontkenning moet dus op een andere plaats staan omdat het mogelijk is dat een werknemer
aan meerdere projecten werkt.
Ook de dubbele ontkenning (niet behorend bij de groep waarvoor niet geldt ... ) vinden veel
mensen op het eerste gezicht lastig te formuleren in SQL. Toch is ook hiervoor na enig
denkwerk op vrij eenvoudige wijze een oplossing te formuleren.
Stel dat we een overzicht willen hebben van alle werknemers die nog nooit aan een project
hebben gewerkt dat niet de code 110 had. We zien dan al vrij snel dat het bij een dergelijke
vraagstelling eigenlijk gaat om een 'alleen maar' vraag die we in een vorige paragraaf al
besproken hebben en dus ook op een vergelijkbare manier op kunnen lossen :
Hoofdstuk: VEEL VOORKOMENDE PROBLEMEN MET DE SELECT OPDRACHT
Dat levert bij onze database bijvoorbeeld ook werknemer 26 (VAN GEEL) op, terwijl die wel
degelijk aan project 110 werkt! Als we goed kijken zien we dan ook dat met de bovenstaande
SELECT opdracht niet gevraagd wordt welke werknemers niet aan project 110 werken, maar
welke werknemers aan een project werken dat NIET de PROJ_CODE 110 heeft. Dat betekent
dus dat alle werknemers die aan een project werken met een andere PROJ_CODE dan 110
geselecteerd worden, dus ook de werknemers die naast een ander project ook aan project 110
werken.
6
2
Database SQL
1 mei 2010
SELECT CODE,NAAM
FROM WERKNEMERS
WHERE CODE NOT IN
(
SELECT CODE
FROM WERK
WHERE PROJ_CODE != '110'
)
SELECT CODE,NAAM
FROM WERKNEMERS
WHERE CODE NOT IN
(
SELECT CODE
FROM WERK
WHERE PROJ CODE!= '110'
)
AND
CODE IN
(
SELECT CODE
FROM WERK
)
OPDRACHTEN
Geef een opdracht in SQL voor het opvragen van de volgende overzichten uit de
WERKNEMERS, WERK, PROJECTEN en SCHALEN tabellen
1. De namen van werknemers die niet aan een project werken dat in UTRECHT wordt
uitgevoerd.
2. De namen van werknemers die aan een project werken dat in een andere plaats dan
UTRECHT wordt uitgevoerd.
3. De namen van werknemers die nog nooit aan een project geleid door werknemer 35
hebben meegewerkt.
4. De namen van werknemers die nog nooit aan een project hebben meegewerkt
waarvoor een budget lager dan 100.000 gulden beschikbaar was.
5. De namen van werknemers die nog nooit aan een project hebben gewerkt dat niet
door werknemer 35 werd geleid.
Hoofdstuk: VEEL VOORKOMENDE PROBLEMEN MET DE SELECT OPDRACHT
Wellicht het enige probleem dat hier nog aan vastzit is dat op grond van deze SELECT opdracht
(zoals in de eerdere paragraaf al aan de orde kwam) ook de werknemers die aan geen enkel
project meewerken geselecteerd worden omdat zij nu eenmaal behoren tot de groep
werknemers wiens CODE niet voorkomt in de groep van werknemers die niet aan project 110
werken; zij werken immers aan geen enkel project. Dit kunnen we vrij eenvoudig oplossen door
de voorgaande SELECT opdracht nog wat uit te breiden
6
3
Database SQL
1 mei 2010
Alle ...
Een lastig probleem vormen tenslotte vraagstellingen die het woord 'alle' in zich hebben.
'Welke klanten hebben alle artikelen besteld 7'
Of
'Welke werknemers werken mee aan alle projecten 7'
Dit probleem kunnen we op twee manieren benaderen.
In de eerste plaats kennen we geen speciale operator om het gebruik van 'alle' mee weer te
geven. We zullen de vraag dus op een 'SQL-achtige' manier moeten omschrijven.
We kiezen dan vrijwel altijd voor de volgende redenering:
Als een werknemer aan alle projecten mee moet werken is er dus geen enkel project waar de
werknemer niet aan meegewerkt heeft.
SELECT CODE,NAAM
FROM WERKNEMERS W
WHERE NOT EXISTS
(
SELECT PROJ_CODE
FROM PROJECTEN
WHERE PROJ_CODE NOT IN
(
SELECT PROJ CODE
FROM WERK
WHERE CODE = WCODE
)
)
Dit behoeft wellicht enige toelichting. Als we bovenstaande opdracht van achter naar voren
lezen, zien we dat in de laatste subquery alle PROJ_CODEs van de werknemer die op het punt
staat geselecteerd te worden uit de tabel WERK gehaald worden (Het is immers een
dynamische (gesynchroniseerde) subquery vanwege CODE = WCODE)
Als we dat bijvoorbeeld doen voor werknemer 40 dan zien we dat in de tabel WERK alleen de
PROJ_CODEs 110 en 120 bij de CODE 40 voorkomen. (Gebruik de tabellen om mee te denken!!)
Als we vervolgens de PROJ_CODEs uit de tabel PROJECTEN selecteren waarvoor geldt dat hun
PROJ_CODE niet voorkomt in de zojuist verzamelde groep PROJ_CODEs dan zien we dat alleen
PROJ_CODE 110 en 120 afvallen zodat we de PROLCODEs 130,140 en 150 overhouden.
Als we dan in de hoofdquery, door gebruik te maken van NOT EXISTS, aangeven dat de
subquery niets op mag leveren, zal duidelijk zijn dat werknemer 40 niet geselecteerd kan
worden omdat de subquery een drietal waarden (130,140 en 150) oplevert en dat is beduidend
meer dan niets!
Hoofdstuk: VEEL VOORKOMENDE PROBLEMEN MET DE SELECT OPDRACHT
Zo geformuleerd kunnen we deze vraag wel in SQL stellen
6
4
Database SQL
1 mei 2010
Nog een voorbeeld, nu met werknemer 26 die wel aan alle projecten meewerkt en dus wel
geselecteerd zou moeten worden. We beginnen weer met de laatste subquery, deze levert
voor werknemer 26 de waarden 110,120,130,140 en 150 op.
Vervolgens selecteren we uit de PROJECTEN tabel die PROJ_CODEs die niet in de zojuist
verzamelde waarden voor komen. Omdat we alleen de projecten 110,120,130, 140 en 150
kennen, kunnen we geen enkele waarde uit de PROJECTEN tabel selecteren die niet in de
verzamelde groep waarden voorkomt. Als de subquery niets oplevert, moeten we vanwege het
NOT EXISTS gedeelte in de hoofdquery de CODE van die werknemer selecteren. In dit geval
moet dat dus ook gebeuren. En dat is dan terecht want werknemer 26 werkt aan alle
projecten!
Een andere benadering is niet bij alle SQL implementaties mogelijk. We hebben al eerder
kunnen zien dat het gebruik van group functies aan twee zijden van een operator niet in alle
implementaties is toegestaan. Omdat het in sommige RDBMS-en wel toegestaan is en omdat
het een vereenvoudiging betekent van de vraagstelling, zullen we deze tweede oplossing hier
toch behandelen.
We zouden de vraag dan kunnen herformuleren als:
Deze vraag is vrij eenvoudig te formuleren als we gebruik kunnen maken van de COUNT functie
aan beide zijden van het = teken
SELECT CODE,NAAM
FROM WERKNEMERS
WHERE CODE IN
(
SELECT CODE
FROM WERK
GROUP BY CODE
HAVING COUNT(PROJ_CODE) =
(
SELECT COUNT(PROJ_CODE)
FROM PROJECTEN
)
)
Als we dit weer voor de twee werknemers die we hiervoor hebben behandeld nagaan kunnen
we zien dat voor de werknemer met CODE 40 het aantal verschillende projecten precies 2
bedraagt. Dat komt dus niet overeen met het aantal PROJ_CODEs in de PROJECTEN tabel (5).
Als we dan werknemer 26 bekijken zien we dat bij de CODE 26 precies 5 verschillende
PROJ_CODEs voorkomen in de PROJECTEN tabel. Dat is wel gelijk aan het aantal PROJ_CODEs in
de PROJECTEN tabel en werknemer 26 zal dus wel geselecteerd worden.
Hoofdstuk: VEEL VOORKOMENDE PROBLEMEN MET DE SELECT OPDRACHT
'Geef de werknemers die aan precies evenveel verschillende projecten werken als er projecten
zijn.'
6
5
Database SQL
1 mei 2010
Merk op dat we bij beide COUNT opdrachten geen DISTINCT hoeven te gebruiken omdat de
groepering per CODE er voor zal zorgen dat de bij iedere CODE behorende PROJ_CODEs
verschillend zullen zijn en omdat de PROJ_CODE de sleutel is van de PROJECTEN tabel en dus
uniek zal zijn in iedere rij. (Dit geldt uiteraard alleen als onze database ook daadwerkelijk
integer is !)
OPDRACHTEN
Geef een opdracht in SQL voor het opvragen van de volgende overzichten uit de
WERKNEMERS, WERK, PROJECTEN en SCHALEN tabellen
Hoofdstuk: VEEL VOORKOMENDE PROBLEMEN MET DE SELECT OPDRACHT
1. De namen van alle medewerkers die meegewerkt hebben aan alle projecten die in
ROTTERDAM worden uitgevoerd.
2. De namen van projecten die geleid worden door alle werknemers uit MAASTRICHT.
3. De codes van alle projecten waaraan door werknemers uit alle in de tabel
WERKNEMERS bekende woonplaatsen wordt gewerkt.
6
6
Database SQL
1 mei 2010
DE DATA DICTIONARY
Het principe van de data dictionary
Bij het gebruik van een RDBMS is het vaak handig om gebruik te maken van de ingebouwde
data dictionary. Eigenlijk is de term data dictionary hier wat verwarrend omdat we ook van een
data dictionary spreken als we het in de gegevensanalyse hebben over alle informatie over
gegevens die in een bepaalde organisatie gebruikt worden. De lezer dient zich dus te realiseren
dat we het in dit hoofdstuk hebben over de door het RDBMS zelf aangemaakte en bijgewerkte
data dictionary.
In deze ingebouwde data dictionary wordt bijgehouden welke gebruikers toegang hebben tot
het systeem, welke tabellen er voor iedere gebruiker beschikbaar zijn, uit welke kolommen
iedere tabel bestaat, van welk type iedere kolom is, waar de gegevens zijn opgeslagen
enzovoort. Telkens als er een gebruiker toegang vraagt tot het systeem, als er om een tabel
gevraagd wordt of als er een rij aan een tabel wordt toegevoegd (om slechts een paar
voorbeelden te noemen) zal het RDBMS de data dictionary gebruiken om te controleren of de
gevraagde opdracht mogelijk en/of toegestaan is. Omdat we in de data dictionary te maken
hebben met gegevens over de gegevens in de database, wordt hierbij ook wel gesproken van
metagegevens.
Bovendien zien we dat de data dictionary een steeds belangrijkere rol gaat spelen bij het
opleggen van regels aan de gegevens die in de database worden opgeslagen.
In dit hoofdstuk zullen we vooral stilstaan bij de mogelijkheden van de data dictionary voor het
bewaken van de integriteit van de database. Omdat andere aspecten van de data dictionary
(fysieke opslag, bron van informatie voor de beheerder) in veel gevallen erg verschillend zijn
voor iedere SQL implementatie zal daar verder niet bij worden stilgestaan.
Zoals in hoofdstuk 1 al is aangegeven kan de data dictionary gebruikt worden om de gegevens
die in de database worden opgeslagen aan bepaalde regels te onderwerpen. We hebben het
hierbij over beperkingen die we op willen leggen aan de gegevens die worden opgeslagen, in
het Engels gebruiken we hiervoor de term constraint (beperking).
Al deze beperkingen worden bij het definiëren van de tabel (CREATE TABLE) of door middel van
het wijzigen van de tabel (ALTER TABLE) vastgelegd. De in deze paragraaf te bespreken
beperkingen vormen een uitbreiding op de al behandelde NOT NULL beperking.
Voor de op te leggen beperkingen kunnen we gebruik maken van de volgende mogelijkheden:
PRIMARY KEY, UNIQUE, FOREIGN KEY en CHECK.
Hoofdstuk: DE DATA DICTIONARY
De data dictionary als bewaker van de database.
6
7
Database SQL
1 mei 2010
Door de toevoeging van PRIMARY KEY dwingen we af dat alleen unieke waarden die bovendien
niet onbekend mogen zijn, in deze kolom worden opgenomen:
CREATE TABLE WERKNEMERS
(CODE CHAR(3) PRIMARY KEY, NAAM CHAR(15) NOT NULL)
De toevoeging UNIQUE zorgt er voor dat alleen unieke waarden worden opgenomen in de
desbetreffende kolom. In tegenstelling tot PRIMARY KEY moeten we bij UNIQUE wel de
toevoeging NOT NULL gebruiken als we deze kolom altijd ingevuld willen hebben:
CREATE TABLE PROJECTEN
(PROJ_CODE CHAR(3) PRIMARY KEY, PROJ_NAAM CHAR(15) NOT NULL
UNIQUE )
Door gebruik te maken van
FOREIGN KEY <kolomnaam, ... >
REFERENCES <tabelnaam> {<kolomnaam, ... >}
kunnen we de eerder besproken referentiële integriteit afdwingen.
CREATE TABLE PROJECTEN
(PROJ_CODE CHAR(3) PRIMARY KEY, PROJ_NAAM CHAR(15) NOT NULL
UNIQUE, PROJ_LEIDER CHAR(3),
FOREIGN KEY(PROJ_LEIDER) REFERENCES WERKNEMERS(CODE))
zorgt er voor dat bij iedere toevoeging en/of wijziging gecontroleerd wordt of de in te vullen
projectleider ook een bestaande werknemer is.
Met behulp van CHECK kunnen we de gegevens die ingevoerd worden controleren voordat ze
worden geaccepteerd.
CREATE TABLE WERKNEMERS (CODE CHAR(3) PRIMARY KEY, NAAM CHAR(15)
NOT NULL, CHECK (MOD(CODE,10) = 0), CHECK NAAM = UPPER(NAAM))
Omdat het in sommige gevallen onmogelijk is om bij het definiëren van de tabel al te verwijzen
naar een andere tabel, zullen we soms gebruik moeten maken van het ALTER TABLE
commando. Dit is bijvoorbeeld het geval als we in de WERKNEMERS tabel op willen nemen tot
welke afdeling een medewerker behoort en in een AFDELINGEN tabel willen opnemen welke
werknemer het hoofd van die afdeling is. Op het moment dat we de WERKNEMERS tabel
definiëren (er van uit gaande dat we dat als eerste doen) kunnen we nog niet opnemen
FOREIGN KEY AFDELING CHAR(3) REFERENCES AFDELINGEN(CODE) omdat de
AFDELINGEN tabel op dat moment nog niet bestaat. De volgorde omdraaien heeft geen zin
omdat dan bij het definiëren van de AFDELINGEN tabel de WERKNEMERS tabel nog niet bestaat
en we dus niet op kunnen nemen HOOFD CHAR(3), FOREIGN KEY (HOOFD)
REFERENCES WERKNEMERS(CODE). We lossen dit op door - nadat we de WERKNEMERS en
de AFDELINGEN tabellen hebben gedefinieerd - een ALTER TABLE opdracht uit te voeren:
Hoofdstuk: DE DATA DICTIONARY
zorgt er voor dat alleen codes voor werknemers gebruikt worden die een meervoud van 1 0 zijn
(rest na deling door 10 (MODulus) moet 0 zijn) en bewaakt dat alle namen met hoofdletters
worden ingevoerd.
6
8
Database SQL
1 mei 2010
ALTER TABLE WERKNEMERS
ADD (FOREIGN KEY (AFDELING) REFERENCES AFDELINGEN(CODE))
Hoofdstuk: DE DATA DICTIONARY
In ORACLE bijvoorbeeld kan vanaf versie 7 dit probleem opgelost worden door gebruik te
maken van de opdracht CREATE SCHEMA. Daarmee worden alle CREATE TABLE opdrachten als
één opdracht gezien en bestaat het hiervoor geschetste probleem niet meer.
6
9
Database SQL
1 mei 2010
VIEWS
Het principe van de VIEW
De VIEW is eigenlijk een fenomeen dat zich 'boven' de tabellen bevindt. We zouden kunnen
zeggen dat een VIEW een bepaalde kijk op één of meerdere tabellen weergeeft.
We zouden ons voor kunnen stellen dat er binnen de organisatie waar we onze WERKNEMERS
tabel gebruiken, verschillende personen en/of afdelingen zijn die gebruik willen maken van
gegevens uit onze WERKNEMERS tabel. De personeelsvereniging wil graag alle namen en
adressen, de afdeling personeelszaken wil de namen, adressen en telefoonnummers, de
boekhouding wil de codes en de salarissen, enzovoort.
Nu zouden we voor al deze personen/afdelingen aparte tabellen kunnen gaan maken die zij
dan zouden kunnen raadplegen. Dit heeft echter verschillende nadelen. In de eerste plaats
betekent dit dat de overtolligheid aan gegevens (redundantie) waar we door middel van
normaliseren zo tegen gestreden hebben, weer volledig teniet gedaan wordt omdat we allerlei
gegevens nu weer dubbel of zelfs driedubbel en meer op gaan slaan. Bovendien geeft dit nogal
wat onderhoudsproblemen. Als werknemer 10 verhuist, betekent dit dat we eerst na moeten
gaan in welke tabellen haar adres voorkomt om vervolgens deze wijziging in al die tabellen
door te gaan voeren.
We zouden er dan voor kunnen kiezen om de WERKNEMERS tabel dan maar voor iedereen
beschikbaar te stellen. Ook dit is niet zo'n gelukkige oplossing omdat we dan moeten gaan
bepalen wie welke wijzigingen door mag gaan voeren en bovendien moeten we er voor zorgen
dat een bepaalde wijziging slechts één maal wordt uitgevoerd (tweemaal een loonsverhoging
van 10% voor dezelfde werknemer zal voor die werknemer geen bezwaar zijn maar op die
manier is onze organisatie natuurlijk geen lang leven beschoren). Dat is een stuk lastiger als er
meerdere mensen de beschikking hebben over dezelfde gegevens. We komen hier nog op
terug in als we het hebben over Gegevensbeveiliging.
Om dit soort problemen het hoofd te kunnen bieden, kunnen we gebruik maken van VIEW’s.
Een VIEW is eigenlijk niets anders dan een vastlegging van welke gegevens uit welke tabel (of
tabellen!) gecombineerd moeten worden tot een VIEW. De VIEW krijgt een naam en gedraagt
zich verder volledig alsof het een tabel is. Bij een aantal RDBMS-en kunnen we zelfs via een
VIEW (die dan wel aan enkele voorwaarden moet voldoen) gegevens aan een tabel toevoegen
of gegevens uit een tabel wissen of wijzigen.
Het maken van een VIEW
Bij het maken van een VIEW hoeven we ons eigenlijk alleen maar af te vragen welke naam we
aan de VIEW zullen geven en met welke SELECT opdracht we de VIEW kunnen samenstellen.
Hoofdstuk: VIEWS
Bovendien vindt waarschijnlijk niet iedereen het zo'n prettig idee dat bijvoorbeeld zijn of haar
salaris niet alleen bij de financiële afdeling maar ook bij de personeelsvereniging en alle andere
geledingen inde organisatie bekend is.
7
0
Database SQL
1 mei 2010
Stel dat de eerder genoemde personeelsvereniging de beschikking wil hebben over de namen,
adressen, postcodes en woonplaatsen om de uitnodigingen voor de feestavonden en het
personeelsblad te kunnen versturen. We geven dan de opdracht
CREATE VIEW PERSONEEL(NAAM,ADRES,POSTCODE,WOONPLAATS) AS
SELECT NAAM,ADRES,POSTCODE,WOONPLAATS
FROM WERKNEMERS
Vervolgens geven we het bestuur van de personeelsvereniging toestemming om deze VIEW te
gebruiken (hoe dat werkt wordt later behandeld). Zij kunnen vanaf dat moment de VIEW PERSONEEL gewoon benaderen alsof het een tabel is. Het verschil tussen een VIEW en een tabel
hoeft voor de eindgebruiker dus helemaal niet aan de orde gesteld te worden. De
personeelsvereniging kan nu dus alle namen en adressen opvragen door op te geven:
SELECT *
FROM PERSONEEL
Het belangrijkste verschil met een tabel is eigenlijk dat van een VIEW alleen de definitie (de
CREATE VIEW opdracht dus) bewaard wordt en iedere keer als een gebruiker de VIEW wil
gebruiken zal deze opnieuw worden samengesteld.
Dat heeft niet alleen het voordeel dat de VIEW vrijwel geen ruimte in beslag neemt maar dit
zorgt er ook voor dat de VIEW steeds de meest recente gegevens bevat. Zolang de wijzigingen
maar verwerkt zijn in de WERKNEMERS tabel zullen die ook doorwerken in de VIEW
PERSONEEL.
Niet alleen bij het beperken van het aantal kolommen dat iemand mag zien maar ook om
sommige vragen wat eenvoudiger te kunnen formuleren, kunnen we gebruik maken van de
VIEW.
Stel dat er iemand in onze organisatie is die zeer vaak behoefte heeft aan een overzicht van de
CODE, de NAAM, het SALARIS en het aantal gewerkte UREN van de werknemers. Als hij of zij
gebruik maakt van onze database moet er om deze overzichten te kunnen produceren steeds
een JOIN gemaakt worden van de tabel WERKNEMERS en de tabel WERK. We zouden dit wat
eenvoudiger kunnen maken door de JOIN op te nemen in een VIEW.
CREATE VIEW PROJ_MED (MED_NR,NAAM,SALARIS,PROJECT,UREN) AS
SELECT WERKN EM ERS. CODE, NAAM,SAL, PROJ_ CODE, U REN
FROM WERKNEMERS,WERK
WHERE WERKNEMERS.CODE = WERK.CODE
SELECT *
FROM PROJ_MED
opgegeven worden om het gewenste overzicht te verkrijgen.
Ook voor het maken van rekenkundig bewerkte overzichten kunnen we de VIEW gebruiken. Als
we bijvoorbeeld vaak de behoefte hebben aan overzichten van WERKNEMERS met hun
jaarsalaris kunnen we opgeven
Hoofdstuk: VIEWS
Vanaf dat moment kan gewoon
7
1
Database SQL
1 mei 2010
CREATE VIEW SALARISSEN (MEDEW,PER_MAAND,PER_JAAR) AS
SELECT NAAM,SAL,SAL*12
FROM WERKNEMERS
Ook nu is het gevraagde overzicht eenvoudig te produceren door
SELECT *
FROM SALARISSEN
OPDRACHTEN
1. Geef de opdracht voor het maken van een VIEW genaamd ITCZ met daarin de namen
en telefoonnummers van alle medewerkers die aan het ITCZ project meewerken.
2. Geef de opdracht voor het maken van een VIEW genaamd HOOG_SAL waarin
opgenomen zijn de namen en volledige adressen van alle werknemers die meer
verdienen dan hun chef.
Het verwijderen van een VIEW
Het verwijderen van een VIEW is een vrij eenvoudige opdracht. Evenals bij het verwijderen van
een tabel en een index maken we ook hier weer gebruik van een DROP .. , opdracht.
DROP VIEW <naam van de view>
Hoofdstuk: VIEWS
Bij het verwijderen van een VIEW moeten we er rekening mee houden dat eventuele andere
VIEWs die als één van hun bronnen gebruik maken van de nu te verwijderen VIEW niet meer
geldig zijn en dus ook verwijderd moeten worden. Het is afhankelijk van de SQL implementatie
of deze verwijdering automatisch uitgevoerd wordt of dat dit handmatig gedaan moet worden.
7
2
Database SQL
1 mei 2010
GEGEVENS WIJZIGEN
De verschillende mogelijkheden
Naast het benaderen van een RDBMS om overzichten te produceren, willen we natuurlijk ook
nieuwe gegevens in kunnen voeren, gegevens kunnen wijzigen en gegevens kunnen
verwijderen. Dit kan in SQL met de opdrachten INSERT, UPDATE en DELETE. We zullen deze
mogelijkheden in dit hoofdstuk bespreken.
INSERT
Zoals we al hebben kunnen zien, kunnen we een tabel vullen met gegevens door gebruik te
maken van de INSERT opdracht. We hebben daar ook opgemerkt dat dit een vrij omslachtige
manier van werken is die bij de meeste RDBMS-en niet gebruikt zal worden maar vervangen zal
worden door een zogenaamde applicatiegenerator of 'scherm-bouw' mogelijkheid.
De INSERT opdracht is echter ook op een wat minder omslachtige manier te gebruiken. Met
name door voor het vullen van de tabel gebruik te maken van gegevens uit een andere tabel en
door middel van een SELECT opdracht de nieuwe tabel te vullen.
We zouden bijvoorbeeld (hoewel dat niet aan te raden is) een aparte tabel kunnen maken van
alle werknemers uit ROTTERDAM. We moeten dan uiteraard eerst de tabelstructuur definiëren
met een CREATE opdracht :
CREATE TABLE ROTTERDAM(NAAM CHAR(15) NOT NULL, ADRES CHAR(20),
POSTCODE CHAR(7), WOONPLAATS CHAR(20), TELEFOON CHAR(12))
Vervolgens kunnen we de WERKNEMERS tabel gebruiken als 'leverancier' van rijen.
INSERT INTO ROTTERDAM(NAAM, ADRES, POSTCODE, WOONPLAATS,
TELEFOON)
SELECT NAAM,ADRES,POSTCODE,WOONPLAATS, TELEFOON
FROM WERKNEMERS
WHERE WOONPLAATS = 'ROTTERDAM'
OPDRACHTEN
1. Geef de opdracht voor het aanmaken van een tabel genaamd PROJ_RDAM met daarin
opgenomen de kolommen naam, adres, postcode en woonplaats.
2. Geef de opdracht om deze tabel te vullen met de gegevens van alle werknemers die
aan een project in ROTTERDAM werken.
Hoofdstuk: GEGEVENS WIJZIGEN
Door gebruik te maken van een SELECT opdracht in het tweede gedeelte van de INSERT
opdracht vullen we de tabel ROTTERDAM met alle gegevens van alle werknemers die aan de
gestelde voorwaarde voldoen.
7
3
Database SQL
1 mei 2010
UPDATE
Een andere vorm van gegevensbewerking is de UPDATE opdracht waarmee we waarden in
kolommen kunnen wijzigen. Dit is uiteraard met name handig bij het doorvoeren van
wijzigingen als verhuizingen, salarisverhogingen en dergelijke.
Stel dat werknemer 26 van UTRECHT naar GELEEN gaat verhuizen, het nieuwe adres wordt:
BOTERMARKT 14 5989 HJ en het telefoonnummer wordt 046-4186530. Deze wijziging kunnen
we als volgt Invoeren:
UPDATE WERKNEMERS
SET
ADRES='BOTERMARKT 14',
POSTCODE='5989 Hr',
WOONPLAATS = 'GELEEN',
TELEFOON = '046-4186530'
WHERE
CODE = '26'
We kunnen de UPDATE opdracht ook gebruiken om een wijziging door middel van een
rekenkundige bewerking uit te voeren
UPDATE WERKNEMERS
SET SAL = SAL * 1.10
WHERE CHEF = '99'
OPDRACHTEN
Geef de opdrachten voor het aanbrengen van de volgende wijzigingen in de WERKNEMERS,
WERK, PROJECTEN en SCHALEN tabellen
1. Geef alle werknemers die meewerken aan het CAIA project een salarisverhoging van
15%.
2. Halveer het budget van alle projecten die geleid worden door werknemer 35.
3. Verander de postcode van werknemer MAAS in 3085 PD.
4. Geef alle medewerkers die aan een project werken waar ook medewerker 50 aan
meewerkt een salarisverhoging van 250 gulden.
5. Geef alle medewerkers die werken aan het project dat geleid wordt door werknemer
MERK een zelfde salaris als MERK.
Hoofdstuk: GEGEVENS WIJZIGEN
Zo wordt bij alle werknemers met als chef 99 een salarisverhoging van 10% doorgevoerd. Het
spreekt voor zich dat we in dit soort gevallen uiterst voorzichtig moeten zijn met het
formuleren van onze voorwaarden.
7
4
Database SQL
1 mei 2010
DELETE
Tenslotte moeten we ook de mogelijkheid hebben om rijen uit tabellen te verwijderen. Dat
kunnen we vrij eenvoudig doen door gebruik te maken van de DELETE opdracht.
We zouden bijvoorbeeld werknemer 40 kunnen wissen door in te geven:
DELETE FROM WERKNEMERS WHERE CODE = '40'
Twee dingen zijn hierbij van belang. In de eerste plaats moeten we uiteraard uitermate
zorgvuldig zijn met het formuleren van de voorwaarde. Relationele databases zijn wat dat
betreft vergelijkbaar met mensen: iedereen voldoet aan geen enkele voorwaarde en vrijwel iedereen voldoet aan onduidelijk omschreven voorwaarden! De opdracht
DELETE FROM WERKNEMERS
is dan ook een zeer snelle methode om alle rijen uit de WERKNEMERS tabel te verwijderen.
In de tweede plaats komt hier het begrip referentiële integriteit weer aan de orde. Zouden we
de gegevens van werknemer 40 uit de WERKNEMERS tabel wissen zonder daarbij eerst te
controleren of er in de tabel WERK geen rijen meer voorkomen met als CODE de waarde 40,
dan kan de situatie ontstaan dat we een aantal uren, besteed aan een project, hebben
geregistreerd waarvan we niet weten door wie ze zijn uitgevoerd. Daar zal de opdrachtgever
van het project niet zo blij mee zijn.
Hoofdstuk: GEGEVENS WIJZIGEN
OPDRACHTEN
Geef een opdracht in SQL voor het uitvoeren van de volgende opdrachten met de
WERKNEMERS, WERK, PROJECTEN en SCHALEN tabellen
1. Verwijder alle rijen uit de WERK tabel waar werknemer 26 bij betrokken is.
2. Verwijder werknemer 26 uit de WERKNEMERS tabel.
3. Verwijder alle werknemers die niet aan een project werken, behalve werknemer 99.
4. Verwijder alle gegevens over werknemers die nog nooit aan een project in UTRECHT
hebben gewerkt uit de WERK tabel.
5. Verwijder alle gegevens uit de WERK tabel van werknemers die aan een project werken
waar werknemer 26 nog nooit aan meegewerkt heeft.
7
5
Database SQL
1 mei 2010
GEGEVENS BEVEILIGEN
Vormen van gegevensbeveiliging
Uiteraard is het belangrijk om er zorg voor te dragen dat de gegevens in de database beveiligd
zijn tegen verlies of onbevoegd gebruik. We hebben het dan eigenlijk over twee soorten
gegevensbeveiliging: er mogen geen gegevens verloren raken als gevolg van één of andere
calamiteit: de bescherming tegen verlies dus. Bovendien mogen gegevens niet geraadpleegd
worden door personen die daar geen bevoegdheid voor hebben: de bescherming tegen
ongeoorloofd gebruik. Op beide vormen van beveiliging zal in dit hoofdstuk nader worden
ingegaan.
Bescherming tegen verlies
Vrijwel alle RDBMS-en kennen de mogelijkheid om gegevens te exporteren en dus op diskette
of band vast te leggen, zodat de gegevens op een veilige plaats opgeborgen kunnen worden (de
backup zoals dat in fraai Nederlands heet). Het spreekt voor zich dat dit van groot belang is; we
weten zeker dat iedere computer op een dag stuk gaat, we weten alleen niet wanneer!
Naast deze, in vrijwel ieder programma aan te treffen mogelijkheden, kennen we in vrijwel alle
RDBMS-en die met SQL werken de ROLLBACK en COMMIT mogelijkheden.
De wijzigingen die we aanbrengen als we een database met SQL benaderen, worden in het
werkgeheugen (in de buffers) uitgevoerd en nog niet daadwerkelijk weggeschreven naar het
externe geheugen (de disk).
Als er nu iets echt misgaat (we hebben een tabel met 89765 rijen in één opdracht volledig
gewist) kunnen we in veel gevallen met de opdracht
ROLLBACK
de wijzigingen weer ongedaan maken.
Bovendien houdt het RDBMS vaak een soort administratie bij (een logfile) waarin geregistreerd
wordt welke wijzigingen er allemaal plaatsvinden. Dit kan na een stroomstoring gebruikt
worden om de nog niet definitief doorgevoerde wijzigingen nogmaals uit te voeren.
COMMIT
geven. Dan worden alle wijzigingen ook daadwerkelijk weggeschreven en kunnen we ook geen
ROLLBACK meer uitvoeren.
Autorisatie van gebruik
Om gegevens te beschermen tegen gebruik door onbevoegden kennen we uiteraard de al
besproken VIEW. Toch is alleen het maken van VIEWs niet voldoende. Vandaar dat in RDBMSen die met SQL werken een geheel aan bevoegdheden en bevoegdheidsniveaus is opgenomen
waardoor het mogelijk wordt om gegevens afdoende te beschermen tegen ongeoorloofd
gebruik.
Hoofdstuk: GEGEVENS BEVEILIGEN
Als we er op een bepaald moment echt zeker van willen zijn dat alle wijzigingen ook op disk
worden weggeschreven kunnen we de opdracht
7
6
Database SQL
1 mei 2010
Om te beginnen zal iedere gebruiker bij het RDBMS bekend moeten zijn voordat hij of zij ook
maar 'verbinding' kan krijgen met het RDBMS. Dat betekent dat iedere gebruiker zich bekend
moet maken aan het RDBMS door middel van een gebruikers naam en een wachtwoord. Een
gebruiker die daartoe de bevoegdheid heeft, kan nieuwe gebruikers introduceren door gebruik
te maken van
GRANT CONNECT TO <gebruikersnaam> IDENTIFIED BY <wachtwoord>
Zo zouden we dus een nieuwe gebruiker KARIN met als wachtwoord SNOOPY als volgt kunnen
introduceren
GRANT CONNECT TO KARIN IDENTIFIED BY SNOOPY
Vanaf dat moment kan KARIN gebruik maken van het RDBMS en tabellen en dergelijke
raadplegen waarvoor haar ook weer apart toestemming is verleend. Als dat niet gebeurd is,
kan zij dus nog niets!
We kunnen andere gebruikers het recht geven om bepaalde bewerkingen uit te voeren op
tabellen waarvan wij eigenaar zijn (dat wil zeggen dat we de CREATE opdracht hebben
gegeven).
Een andere gebruiker zou dus KARIN de bevoegdheid kunnen geven om een tabel te gaan
gebruiken. Dit verlenen van bevoegdheden omvat een aantal mogelijkheden. We kunnen de
volgende bevoegdheden verlenen
SELECT
INSERT
UPDATE
DELETE
ALTER
INDEX
Iemand mag de tabel raadplegen
Iemand mag rijen toevoegen
Iemand mag wijzigingen aanbrengen
Iemand mag rijen verwijderen
Iemand mag de structuur van de tabel wijzigen
Iemand mag indices aanmaken bij de tabel
Zo zou iemand KARIN dus toestemming kunnen geven om de tabe WERKNEMERS te raadplegen
door in te geven
Uiteraard hoeven we hier geen wachtwoord toe te voegen.
De UPDATE bevoegdheid kan zelfs per kolom gegeven worden. Dus we zouden KARIN
toestemming kunnen geven om in de kolom SAL uit de tabel WERKNEMERS wijzigingen aan te
brengen
GRANT UPDATE ON WERKNEMERS(SAL) TO KARIN
Als we KARIN alle bevoegdheden voor de tabel WERKNEMERS willen geven, hoeven we
gelukkig niet alle mogelijkheden op te sommen maar kunnen we volstaan met
GRANT ALL ON WERKNEMERS TO KARIN
We kunnen deze bevoegdheden aan alle andere gebruikers verlener met de opdracht
GRANT ALL ON WERKNEMERS TO PUBLIC
Hoofdstuk: GEGEVENS BEVEILIGEN
GRANT SELECT ON WERKNEMERS TO KARIN
7
7
Database SQL
1 mei 2010
Ook kunnen we aangeven dat KARIN de aan haar verleende bevoegdheden weer aan andere
gebruikers mag doorgeven
GRANT ALL ON WERKNEMERS TO KARIN WITH GRANT OPTION
In de situatie die nu is ontstaan kan KARIN nog steeds niets anders doen dan de tabel
WERKNEMERS gebruiken. Om zelf ook tabellen aan te kunnen maken moet zij een hogere
bevoegdheid krijgen. Dat doen we door de volgende opdracht op te geven
GRANT RESOURCE TO KARIN
We kunnen KARIN ook de hoogst mogelijke bevoegdheid geven met de opdracht
GRANT DBA TO KARIN
Vanaf dat moment heeft KARIN de Database Administrator bevoegdheid en kan nu ook nieuwe
gebruikers introduceren, tabellen van anderen raadplegen en bewerken, wachtwoorden van
andere gebruikers opvragen enzovoort.
Wel moeten we er rekening mee houden dat een tabel die we niet zelf aangemaakt hebben,
voorafgegaan moet worden door de naam van de eigenaar van die tabel. Stel dat gebruiker
PETER aan KARIN de bevoegdheid heeft verleend om de tabel BESTELLINGEN (die hij
aangemaakt heeft) te raadplegen door
GRANT SELECT ON BESTELLINGEN TO KARIN
dan zal KARIN, als zij opgeeft
SELECT * FROM BESTELLINGEN
de mededeling krijgen dat deze tabel niet bestaat! Zij moet opgeven
SELECT * FROM PETER. BESTELLINGEN
Dit probleem kan KARIN oplossen door gebruik te maken van een synoniem voor die tabel.
Bijvoorbeeld
CREATE SYNONYM BESTELLINGEN FOR PETER.BESTELLINGEN
SELECT * FROM BESTELLINGEN
Alle hiervoor genoemde bevoegdheden kunnen iemand weer ontnomen worden door gebruik
te maken van
REVOKE <bevoegdheid> FROM <gebruikersnaam>
Zo zouden we KARIN de toegang tot de database weer kunnen ontzeggen door
REVOKE CONNECT FROM KARIN
of (iets minder grof)
REVOKE SELECT ON BESTELLINGEN FROM KARIN
Hoofdstuk: GEGEVENS BEVEILIGEN
Vanaf dat moment kan zij gewoon opgeven
7
8
Database SQL
1 mei 2010
VRAGEN
1. Waarom zouden we geen wachtwoord op moeten geven bij het verlenen van
toestemming aan een andere gebruiker om onze tabel(len) te raadplegen?
Hoofdstuk: GEGEVENS BEVEILIGEN
OPDRACHTEN
1. Introduceer de nieuwe gebruiker SCOTT met als wachtwoord TIGER.
2. Geef gebruiker SCOTT toestemming om de gehele tabel WERK te raadplegen.
3. Geef gebruiker SCOTT toestemming om de telefoonnummers van werknemers in de
WERKNEMERS tabel te wijzigen.
4. Geef gebruiker SCOTT toestemming om zelf tabellen aan te maken
7
9
Download