1. Geef code en omschrijving van alle cursussen die precies vier dagen duren.



Vergelijkbare documenten
Oefeningen Hoofdstuk 1 : Select

Zelftest SQL Workshop

Zelftest SQL Workshop

SQL Aantekeningen 3. Maarten de Rijke 22 mei 2003

SQL is opgebouwd rond een basisinstructie waaraan één of meerdere componenten worden toegevoegd.

Query SQL Boekje. Fredrik Hamer

Guido Geurts Mark Bernaerts

Structured Query Language (SQL)

[TOETS SQL INLEIDING]

Elfde-Liniestraat Hasselt Schooljaar TINFO POKER GAME Oracle Scripts

SQL manipulatietaal. We kunnen er data mee toevoegen, wijzigen en verwijderen uit een database.

DBMS. DataBase Management System. Op dit moment gebruiken bijna alle DBMS'en het relationele model. Deze worden RDBMS'en genoemd.

SQL: oefenen queries

1. Inleiding Inleiding SQL Inleiding Database, databaseserver en databasetaal Het relationele model...

= > >= < <= BETWEEN IS NULL IS NOT NULL

SQL STATEMENTS. Deze kolom kan grote stukken tekst aan en is bedoeld om tekst erin de plaatsen. Geheel getal, bijvoorbeeld 8, 63, 835 NUMERIC

Toon TITEL, JAAR en PLATVORM van GAMES die voor het jaar 2000 uitkwamen op Nintendo 64

Puzzelen met SQL: Fileleed

Databases - Inleiding

Les S-02: Meer geavanceerde SQL-instructies

Structured Query Language

Donderdag 28-jan 6:30 8:27 11:54 12:54 15:34 17:23 19:20

12. Meer dan één tabel gebruiken en sub-queries

Puzzelen met SQL 38. De Muzieklijst, deel 2 PUZZELEN MET SQL

Zelftest SQL. Document: n0453test.fm 19/04/2012. ABIS Training & Consulting P.O. Box 220 B-3000 Leuven Belgium

DBMS SQL. Relationele databases. Sleutels. DataBase Management System. Inleiding relationele databases. bestaan uit tabellen.

Introductie (relationele) databases

Sparse columns in SQL server 2008

Microsoft SQL. opdracht. Regio College Zaanstreek Waterland Afdeling ICT Opleidingen

Correctievoorschrift VWO NederlandsNederl. Informatica. Tijdvak 1 Woensdag 17 mei uur. College-examen schriftelijk.

Databases en SQL Foundation (DBSQLF.NL)

Data Manipulation Language

SQL & Relationele datamodellen in interactieve media

oefeningen TOP2000 antwoorden

SQL.

Toelichting Validatieregels DBC GGZ RG12

Inhoud. Voorwoord Belangrijkste kenmerken van dit boek De opzet van dit boek Over de auteur Woord van dank

Versieperikelen. Bijlage C

SQL & Datamodelleren

hoofdstuk 9 referentiële integriteit waarborgen overige constraints 9.1 Referentiële integriteit relationele databases 9.1

Puzzelen met SQL DEV. Crash SQL Investigation

Les 11 : Basis SQL (deel2).

Data Manipulatie. Query Talen. / Informatica

TECHNISCHE UNIVERSITEIT EINDHOVEN. Faculteit Wiskunde en Informatica

Zelftest DB2 for z/os basiscursus

SQL: query taal met. woorden. ISO SQL: Structured Query Language. de SQL basis query structuur. voorbeeld: doel: intuitieve query taal

Databank - Basis 1. Inhoud. Computervaardigheden en Programmatie. Hoofdstuk 4 Databank - Basis. Terminologie. Navigeren door een Venster

databases & SQL - antwoorden

ISO SQL: Structured Query Language

Inhoud. Voorwoord 1 Belangrijkste kenmerken van dit boek 1 De opzet van dit boek 1 Over de auteurs 2 Woord van dank 2

Informatica toets vwo 6 Databases

Les 2 Eenvoudige queries

11. Het selecteren van gegevens deel II

DATAMODEL SQL. Middelbare School. Versie 1.0 Datum 30 oktober 2010 Auteur Mark Nuyens, studentnummer: Groep TDI 1

Hoofdstuk 17: Logische & Informatiefuncties en operatoren

Het SQL Leerboek zevende editie Antwoorden op Opgaven

Integriteitsbewaking bij een relationele database

SQL datadefinitietaal

ISO Query By Example

Inleiding Databases en Data Base Management Systems Tabellen Wat is SQL?... 5

Computervaardigheden. Universiteit Antwerpen. Computervaardigheden en Programmatie. Grafieken en Rapporten 1. Inhoud. Anatomie van een databank

Secure Application Roles

Errata en opmerkingen Relationele Databases en SQL 1e druk

oefeningen eredivisie antwoorden

Datamodelleren en databases 2011

SQL opgaven. Relationele model: Opgaven:

Computerclub Volwassenen, Jeugd en Informatica vzw

SQL. Datamodellering 2008

SQL. Wat is SQL? Geschiedenis SQL SQL DMO Datamodellering 2008

EXIN Databases en SQL Foundation

Oracle Analytische Functies

U ziet de progressie van de download aan de groene blokjes in het balkje helemaal onder aan de pagina.

1. * Database worden vaak gebruikt in Client-Server architectuur.

Release Notes. Afdrukdatum: 2011/12/20

Relationele databases

2 Specificatie In deze tabel staat voor welk crebotraject de leereenheid is gemaakt Crebotraject code: 95311

In tabel 1 zie je de eenmaandsrendementen van het aandeel LUXA over 2005, steeds afgerond op twee decimalen.

Les S-01: De basisbeginselen van SQL

Miniles gegevensbanken bevragen met SQL

PL/SQL. Declaraties van variabelen. Structuur PL/SQL is een blok-georiënteerde taal: Toekenningen

Vragen hoofdstuk 1: Resultaat

Hoofdstuk 13: Sorteren & Filteren* 2010

Correctievoorschrift HAVO Informatica. Tijdvak 1 Woensdag 9 mei uur. College-examen schriftelijk.

NHibernate als ORM oplossing

Zelftest Oracle basiscursus

Hoofdstuk: 1 Principes van databases

Maak een analyse van deze gegevens door middel van ER-modellering.

Wijzigingen Universe OSIRIS Manager versie /01 mei 2012

Wat zijn de verschillen tussen SPSS 9 en SPSS 10?

2 Specificatie In deze tabel staat voor welk crebotraject de leereenheid is gemaakt Crebotraject code: 95311

Data Definition Language

6. Het maken van een database

VERSCHILLENDE TARIEVEN VOOR MEER WINST

Practicumopgave 3: SAT-solver

Informatie verwerking en databases RDBMS en tabellen... 8 SQL SELECT... 8 SQL WHERE SQL INSERT SQL UPDATE SQL DELETE...

Datum, Tijd en Timer-object

Digitaal Staatsexamen VWO 2010

Het omzetten van een ER-diagram naar SQL

Spiekboekje Excel Query SQL

Transcriptie:

Antwoorden Deze bijlage geeft de antwoorden van de opgaven waarmee de hoofdstukken 4, 5, 7, 8, 9, en 10 zijn afgesloten. Waar dat van toepassing is geven we alternatieve oplossingen aan, evenals waarschuwingen voor mogelijke fouten. Het is ondoenlijk om per opgave alle goede oplossingen op te nemen; de mogelijkheden van de taal SQL zijn daartoe te uitgebreid. Dit betekent dat het heel goed mogelijk is dat bepaalde opgaven op een volstrekt andere manier worden aangepakt en opgelost. Vergelijking van de resultaattabellen is dan een mogelijkheid om de correctheid te controleren. Pas echter op: als een query het goede resultaat geeft, wil dat nog niet zeggen dat de query correct geformuleerd is: foute oplossingen kunnen - per ongeluk - de juiste rijen opleveren. Dit zijn de meest verraderlijke queries, omdat ze op een onverwacht moment verkeerde oplossingen kunnen produceren. De opgaven zijn hier en daar beslist moeilijk. We gebruiken als het motto dat u zelf voldoende eenvoudige opdrachten kunt verzinnen om uw kennis te testen. Van een paar opgaven is het begrijpen van de gegeven oplossing al een hele prestatie. Antwoorden opgaven paragraaf 4.10 1. Geef code en omschrijving van alle cursussen die precies vier dagen duren. select code, omschrijving 2 from cursussen 3 where lengte = 4; CODE OMSCHRIJVING ---- -------------------------------------------------- S02 Introductiecursus SQL JAV Java voor Oracle ontwikkelaars GEN Systeemgeneratie 2. Geef alle medewerkers, alfabetisch gesorteerd op functie, en per functie op leeftijd (van jong naar oud). select * 2 from medewerkers 3 order by functie, gbdatum desc; MNR NAAM VOORL FUNCTIE CHEF GBDATUM MAANDSAL COMM AFD ---- ------------ ----- ---------- ---- ----------- -------- ---- --- 7900 JANSEN R BOEKHOUDER 7698 03-DEC-1969 800 30 7934 MOLENAAR TJA BOEKHOUDER 7782 23-JAN-1962 1300 10 7839 DE KONING CC DIRECTEUR 17-NOV-1952 5000 10 7566 JANSEN JM MANAGER 7839 02-APR-1967 2975 20 7782 CLERCKX AB MANAGER 7839 09-JUN-1965 2450 10 7698 BLAAK R MANAGER 7839 01-NOV-1963 2850 30 7876 ADAMS AA TRAINER 7788 30-DEC-1966 1100 20 7369 SMIT N TRAINER 7902 17-DEC-1965 800 20 7788 SCHOTTEN SCJ TRAINER 7566 26-NOV-1959 3000 20 7902 SPIJKER MG TRAINER 7566 13-FEB-1959 3000 20 7844 DEN DRAAIER JJ VERKOPER 7698 28-SEP-1968 1500 0 30 7521 DE WAARD TF VERKOPER 7698 22-FEB-1962 1250 500 30 7499 ALDERS JAM VERKOPER 7698 20-FEB-1961 1600 300 30 Academic Service, Den Haag 1

7654 MARTENS P VERKOPER 7698 28-SEP-1956 1250 1400 30 3. Welke cursussen zijn in Utrecht en/of in Maastricht uitgevoerd? select cursus 2 from uitvoeringen 3 where locatie in ('UTRECHT','MAASTRICHT'); CURSUS ------ OAG S02 JAV XML RSO 4. Welke medewerkers hebben zowel de Java als de XML cursus gevolgd? Geef hun nummers. select cursist 2 from inschrijvingen 3 where cursus = 'JAV' 4 and cursist in (select cursist 5 from inschrijvingen 6 where cursus = 'XML'); CURSIST -------- 7499 NB: Er zijn diverse oplossingen mogelijk, bijvoorbeeld met twee subqueries. Duidelijk moge zijn dat een oplossing met AND of OR op rijniveau fout is! 5. Geef de naam en voorletters van alle medewerkers, behalve van R. Jansen. select naam, voorl 2 from medewerkers 3 where not (naam = 'JANSEN' and voorl = 'R'); NAAM VOORL ------------ ----- SMIT N ALDERS JAM DE WAARD TF JANSEN JM MARTENS P BLAAK R CLERCKX AB SCHOTTEN SCJ DE KONING CC DEN DRAAIER JJ ADAMS AA SPIJKER MG MOLENAAR TJA Academic Service, Den Haag 2

Alternatief zonder haakjes (let op: met OR): select naam, voorl 2 from medewerkers 3 where naam <> 'JANSEN' or voorl <> 'R'; 6. Geef nummer, functie, en geboortedatum van alle medewerkers die vóór 1960 geboren zijn, en trainer of verkoper zijn. select mnr, functie, gbdatum 2 from medewerkers 3 where gbdatum < to_date('01-jan-1960','dd-mon-yyyy') 4 and functie in ('TRAINER','VERKOPER'); MNR FUNCTIE GBDATUM ----- ---------- ----------- 7654 VERKOPER 28-SEP-1956 7788 TRAINER 26-NOV-1959 7902 TRAINER 13-FEB-1959 Alternatief (let op de haakjes voor de precedentie): select mnr, functie, gbdatum 2 from medewerkers 3 where gbdatum < to_date('01-jan-1960','dd-mon-yyyy') 4 and (functie = 'TRAINER' or functie = 'VERKOPER'); 7. Geef de nummers van alle medewerkers die niet aan de afdeling opleidingen zijn verbonden. select mnr 2 from medewerkers 3 where afd <> (select anr 4 from afdelingen 5 where naam = 'OPLEIDINGEN'); MNR ----- 7499 7521 7654 7698 7782 7839 7844 7900 7934 8. Geef de nummers van alle medewerkers die de Java cursus niet hebben gevolgd. select mnr 2 from medewerkers 3 where mnr not in (select cursist 4 from inschrijvingen 5 where cursus = 'JAV'); Academic Service, Den Haag 3

MNR ----- 7369 7521 7654 7844 7900 7902 7934 Let op: De volgende twee oplossingen zijn FOUT: select distinct cursist 2 from inschrijvingen 3 where cursist not in (select cursist 4 from inschrijvingen 5 where cursus = 'JAV'); CURSIST -------- 7521 7844 7900 7902 7934 select distinct cursist 2 from inschrijvingen 3 where cursus <> 'JAV'; CURSIST -------- 7499 7521 7566 7698 7788 7839 7844 7876 7900 7902 7934 9. Welke medewerkers hebben voorvoegsels in hun naam? select mnr, naam, voorl 2 from medewerkers 3 where naam like '% %'; MNR NAAM VOORL ----- ------------ ----- 7521 DE WAARD TF 7839 DE KONING CC 7844 DEN DRAAIER JJ Academic Service, Den Haag 4

10a. Welke medewerkers hebben ondergeschikten? select mnr, naam, voorl 2 from medewerkers 3 where mnr in (select chef 4 from medewerkers); MNR NAAM VOORL ----- ------------ ----- 7566 JANSEN JM 7698 BLAAK R 7782 CLERCKX AB 7788 SCHOTTEN SCJ 7839 DE KONING CC 7902 SPIJKER MG 10b. En welke niet? select mnr, naam, voorl 2 from medewerkers 3 where mnr not in (select chef 4 from medewerkers 5 where chef is not null); MNR NAAM VOORL ------- ------------ ----- 7369 SMIT N 7499 ALDERS JAM 7521 DE WAARD TF 7654 MARTENS P 7844 DEN DRAAIER JJ 7876 ADAMS AA 7900 JANSEN R 7934 MOLENAAR TJA 8 rows selected. NB: Let op de laatste WHERE-component; die is beslist nodig! 11. Geef een overzicht van alle uitvoeringen van algemene cursussen (type ALG) in 1999. select * 2 from uitvoeringen 3 where begindatum between date '1999-01-01' 4 and date '1999-12-31' 5 and cursus in (select code 6 from cursussen 7 where type = 'ALG'); CURSUS BEGINDATUM DOCENT LOCATIE ------ ----------- -------- -------------------- OAG 10-AUG-1999 7566 UTRECHT S02 12-APR-1999 7902 DE MEERN S02 04-OCT-1999 7369 MAASTRICHT S02 13-DEC-1999 7369 DE MEERN Academic Service, Den Haag 5

Het jaar 1999 kan ook op een aantal andere manieren worden opgelost door gebruik te maken van functies, die in hoofdstuk 5 aan de orde komen. where to_char(begindatum,'yyyy') = '1999' where extract(year from begindatum) = 1999 where begindatum between to_date('01-jan-1999','dd-mon-yyyy') and to_date('31-dec-1999','dd-mon-yyyy') 12. Geef naam en voorletters van iedereen die ooit bij N. Smit een cursus heeft gevolgd. Aanwijzing: gebruik sub-queries, en werk vervolgens van binnen naar buiten. Dus: bepaal het nummer van N. Smit, zoek dan naar de cursussen die hij heeft gegeven, enzovoorts. select naam, voorl 2 from medewerkers 3 where mnr in 4 (select cursist 5 from inschrijvingen 6 where (cursus,begindatum) in 7 (select cursus,begindatum 8 from uitvoeringen 9 where docent = 10 (select mnr 11 from medewerkers 12 where naam = 'SMIT' 13 and voorl = 'N' 14 ) 15 ) 16 ); NAAM VOORL ------------ ----- ALDERS JAM BLAAK R SCHOTTEN SCJ DE KONING CC JANSEN R SPIJKER MG 13. Wat is de verklaring van het resultaat 'no rows selected' in figuur 4.41? De WHERE-component: 2 where evaluatie not in (1,2,3,NULL) is equivalent met: 2 where evaluatie <> 1 3 AND evaluatie <> 2 4 AND evaluatie <> 3 5 AND evaluatie <> NULL Als we nu een rij hebben met een evaluatie-waarde van 1, 2, of 3 dat is het vrij duidelijk dat één van de eerste drie condities 'onwaar' oplevert, en daarmee levert de WHERE-component als geheel 'onwaar' op. Als de evaluatie-waarde een null-waarde bevat, dan resulteren alle vier de voorwaarden in 'onbekend' en daarmee wordt het eindresultaat ook 'onbekend'. Tot zover geen verrassingen. Academic Service, Den Haag 6

Als de evaluatie-waarde 4 of 5 is (de andere twee toegestane waarden) dan zijn de eerste drie condities alledrie waar, maar levert de laatste conditie 'onbekend' op. De laatste conditie is dus de spelbreker, waardoor het eindresultaat 'onbekend' wordt. waar AND waar AND waar AND onbekend <=> onbekend Antwoorden opgaven paragraaf 5.9 1. Geef van alle medewerkers eerst de achternaam, dan een komma, gevolgd door de voorletter(s) en voorvoegsels. select substr(naam,instr(naam,' ')+1) 2 ', ' voorl ' ' 3 substr(naam,1,instr(naam,' ')-1) 4 as naam 5 from medewerkers; NAAM ----------------------------- SMIT, N ALDERS, JAM WAARD, TF DE JANSEN, JM MARTENS, P BLAAK, R CLERCKX, AB SCHOTTEN, SCJ KONING, CC DE DRAAIER, JJ DEN ADAMS, AA JANSEN, R SPIJKER, MG MOLENAAR, TJA 2. Geef van alle medewerkers hun naam en de geboortedatum, in het formaat zoals bijvoorbeeld 11 April 1997. select naam 2, to_char(gbdatum,'dd Month yyyy') 3 from medewerkers; NAAM TO_CHAR(GBDATUM,'DDMONTHYYYY') ------------ -------------------------------------------- SMIT 17 December 1965 ALDERS 20 Februari 1961 DE WAARD 22 Februari 1962 JANSEN 02 April 1967 MARTENS 28 September 1956 BLAAK 01 November 1963 CLERCKX 09 Juni 1965 SCHOTTEN 26 November 1959 DE KONING 17 November 1952 DEN DRAAIER 28 September 1968 ADAMS 30 December 1966 JANSEN 03 December 1969 SPIJKER 13 Februari 1959 MOLENAAR 23 Januari 1962 Academic Service, Den Haag 7

NB: We kunnen de taal waarin de maandnamen in het resultaat worden weergegeven als volgt veranderen in het Nederlands: alter session set nls_language=dutch; Session altered. 3a. Op welke dag ben (of was!) je precies 10.000 dagen oud? select to_date('11-aug-1954','dd-mon-yyyy') + 10000 2 as "10000 dagen" 3 from dual; 10000 dagen ----------- 27-DEC-1981 We kunnen in plaats van de TO_DATE-functie ook gebruik maken van een DATE-constante: select date '1954-08-11' + 10000 2 as "10000 dagen" 3 from dual; 10000 dagen ----------- 27-DEC-1981 3b. Op welke dag van de week valt/viel dat? select to_char(to_date('11-aug-1954','dd-mon-yyyy')+10000,'day') 2 as "op een:" 3 from dual; op een: --------- zondag Ook hier zouden we op dezelfde wijze gebruik kunnen maken van een DATE-constante. 4. Herschrijf het voorbeeld in figuur 5.24 met gebruikmaking van de NVL2-functie. select naam, maandsal, comm 2, nvl2(comm,12*maandsal+comm,12*maandsal) as jaarsal 3 from medewerkers 4 where naam like '%T%'; NAAM MAANDSAL COMM JAARSAL ------------ -------- ----- -------- SMIT 800 9600 MARTENS 1250 1400 16400 Academic Service, Den Haag 8

SCHOTTEN 3000 36000 5. Herschrijf het voorbeeld in figuur 5.25 met gebruikmaking van CASE-expressies, zowel in de SELECT-component als in de ORDER BY-component. select functie, naam 2, case 3 when maandsal <= 2500 4 then 'goedkoop' 5 else 'duur' 6 end as klasse 7 from medewerkers 8 where gbdatum < date '1964-01-01' 9 order by case functie 10 when 'DIRECTEUR' then 1 11 when 'MANAGER' then 2 12 else 3 13 end; FUNCTIE NAAM KLASSE ---------- ------------ -------- DIRECTEUR DE KONING duur MANAGER BLAAK duur VERKOPER ALDERS goedkoop VERKOPER DE WAARD goedkoop BOEKHOUDER MOLENAAR goedkoop TRAINER SPIJKER duur TRAINER SCHOTTEN duur VERKOPER MARTENS goedkoop Merk op dat we (ongevraagd) ook de TO_DATE-functie hebben vervangen door een DATE-constante. 6. Herschrijf het voorbeeld in figuur 5.21 met gebruikmaking van DATE en INTERVAL constantes, zodat ze onafhankelijk worden van de NLS_DATE_FORMAT instelling. select date '1996-01-29' + interval '1' month as kolom1 2, date '1997-01-29' + interval '1' month as kolom2 3, date '1997-08-11' - interval '3' month as kolom3 4 from dual;, date '1997-01-29' + interval '1' month as kolom2 * ERROR at line 2: ORA-01839: date not valid for month specified c/29/28 2*, date '1997-01-28' + interval '1' month as kolom2 / KOLOM1 KOLOM2 KOLOM3 ----------- ----------- ----------- 29-FEB-1996 28-FEB-1997 11-MAY-1997 Hieruit blijkt dat 29 januari tijdens een niet-schrikkeljaar problemen oplevert; als we 29 in 28 veranderen gaat het goed. Academic Service, Den Haag 9

7. Onderzoek het verschil tussen de datum-formaten WW en IW (weeknummer en ISO weeknummer) aan de hand van een willekeurige datum, en verklaar het eventuele verschil. select sysdate 2, to_char(sysdate, 'ww') as ww 3, to_char(sysdate, 'iw') as iw 4 from dual; SYSDATE WW IW ----------- -- -- 09-FEB-2004 06 07 Het verschil heeft te maken met de manier waarop het weeknummer is gedefinieerd. Het formaat WW laat de eerste week van het jaar altijd op 1 januari beginnen, ongeacht op welke dag van de week dat valt. De ISO standaard hanteert andere regels. Een ISO week begint altijd op een maandag, en rond de jaarwisseling zijn de regels als volgt: Als 1 januari op een vrijdag, zaterdag, of zondag valt dan behoort de week nog tot het vorige jaar, en anders tot het nieuwe jaar. Antwoorden opgaven paragraaf 7.11 1 In figuur 7.10 wordt de constraint M_VERK_CHK op een nogal cryptische manier gedefinieerd. Formuleer dezelfde constraint zonder DECODE en NVL2 te gebruiken. Hier volgen twee mogelijkheden: check ((functie = 'VERKOPER' and comm is not null) or (functie <>'VERKOPER' and comm is null) ) check ((functie = 'VERKOPER' or comm is null) and not (functie = 'VERKOPER' and comm is null) ) 2 Waarom zou de constraint in figuur 7.12 met een apart ALTER TABLE commando moeten worden gedefinieerd? De constraint moet met ALTER TABLE worden gedefinieerd vanwege een kip-ei probleem: een refererende sleutel moet altijd naar een bestaande tabel verwijzen, en er is hier sprake van twee tabellen (MEDEWERKERS en AFDELINGEN) die naar elkaar verwijzen. 3 Het is weliswaar niet behandeld, maar beredeneer waarom bij het gebruik van sequences de pseudo-kolom CURRVAL in een transactie niet kan worden gebruikt zonder eerst een beroep te doen op NEXTVAL. In een multi-user omgeving kunnen diverse database-gebruikers tegelijkertijd gebruik maken van sequences, dus tegelijkertijd met verschillende waarden voor CURRVAL aan het werk zijn; er is dus geen eenduidige globale waarde voor CURRVAL. NEXTVAL is daarentegen op ieder moment gedefinieerd als de volgende sequence-waarde om uit te delen. 4 Hoe komt het dat de kolom evaluatie van de tabel inschrijvingen null-waarden accepteert, ondanks de constraint I_EVAL_CHK (zie figuur 7.16)? Dat komt door de driewaardige logica; een CHECK-conditie kan als resultaat waar, onwaar of onbekend opleveren. Een constraint wordt pas geschonden als de conditie onwaar oplevert. Dit betekent dat voor een verplichte kolom altijd expliciet een NOT NULL-constraint moet worden toegevoegd. Academic Service, Den Haag 10

5 Als een PRIMARY KEY of UNIQUE constraint wordt gedefinieerd, creëert Oracle normaal gesproken impliciet een unieke index om de constraint te kunnen bewaken. Onderzoek wat er gebeurt als een dergelijke constraint DEFERRABLE wordt gedefinieerd. Als PRIMARY KEY of UNIQUE constraints DEFERRABLE worden gedefinieerd, creëert Oracle nietunieke indexen. Indexen moeten namelijk onmiddellijk worden bijgewerkt, zodat tijdens een transactie tijdelijk dubbele waarden in de index moeten kunnen optreden. 6 Met behulp van functie-gebaseerde indexen kunnen we "conditionele uniciteit" implementeren. Maak een unieke index op de INSCHRIJVINGEN-tabel die er voor zorgt dat de OAG-cursus maar één keer mag worden gevolgd. create unique index oag_inschr on inschrijvingen 2 ( case cursus when 'OAG' then cursist else null end 3, case cursus when 'OAG' then cursus else null end ); Index created. De truc is om een index te bouwen op combinaties (cursist, cursus) waarbij we alle niet-oag inschrijvingen negeren. Test de oplossing met het volgende commando (dat zou moeten falen): insert into inschrijvingen values (7900,'OAG',sysdate,null); insert into inschrijvingen values (7900,'OAG',sysdate,null) * ERROR at line 1: ORA-00001: unique constraint (BOEK.OAG_INSCHR) violated Antwoorden opgaven paragraaf 8.10 1 Produceer een overzicht van alle cursusuitvoeringen; geef de cursuscode, de begindatum, de cursuslengte, en de naam van de docent. select c.code 2, u.begindatum 3, c.lengte 4, m.naam as docent 5 from medewerkers m 6, cursussen c 7, uitvoeringen u 8 where u.docent = m.mnr 9 and u.cursus = c.code; CODE BEGINDATUM LENGTE DOCENT ---- ----------- -------- ------------ XML 03-FEB-2000 2 SMIT S02 13-DEC-1999 4 SMIT S02 04-OKT-1999 4 SMIT OAG 10-AUG-1999 1 JANSEN JAV 13-DEC-1999 4 JANSEN RSO 24-FEB-2001 2 SCHOTTEN PLS 11-SEP-2000 1 SCHOTTEN JAV 01-FEB-2000 4 ADAMS S02 12-APR-1999 4 SPIJKER OAG 27-SEP-2000 1 SPIJKER Academic Service, Den Haag 11

NB: Als we ook de cursusuitvoeringen willen zien met onbekende docent, kunnen we deze oplossing als volgt aanpassen: select DISTINCT c.code 2, u.begindatum 3, c.lengte 4, case when u.docent is not null 5 then m.naam 6 else null 7 end as docent 8 from medewerkers m 9, cursussen c 10, uitvoeringen u 11 where coalesce(u.docent,-1) in (m.mnr,-1) 12 and u.cursus = c.code; CODE BEGINDATUM LENGTE DOCENT ---- ----------- -------- ------------ ERM 15-JAN-2001 3 JAV 13-DEC-1999 4 JANSEN JAV 01-FEB-2000 4 ADAMS OAG 10-AUG-1999 1 JANSEN OAG 27-SEP-2000 1 SPIJKER PLS 11-SEP-2000 1 SCHOTTEN PRO 19-FEB-2001 5 RSO 24-FEB-2001 2 SCHOTTEN S02 12-APR-1999 4 SPIJKER S02 04-OKT-1999 4 SMIT S02 13-DEC-1999 4 SMIT XML 03-FEB-2000 2 SMIT XML 18-SEP-2000 2 Regel 11 is misschien op het eerste oog niet zo duidelijk; het maakt de join tussen UITVOERINGEN en MEDEWERKERS iets soepeler. We kunnen in plaats van 1 ook een willekeurig ander getal gebruiken, mits het geen bestaand medewerkernummer kan zijn. Merk ook op dat dit de toevoeging van DISTINCT noodzakelijk maakt. 2 Geef in twee kolommen naast elkaar de naam van elke cursist die een S02 cursus heeft gevolgd, met de naam van de docent. De onderstaande oplossing gebruikt de ANSI/ISO join syntax, voor de variatie: select m.naam as deelnemer 2, d.naam as docent 3 from medewerkers d 4 join 5 uitvoeringen u on (u.docent = d.mnr) 6 join 7 inschrijvingen i using (cursus, begindatum) 8 join 9 medewerkers m on (i.cursist = m.mnr) 10 where cursus = 'S02'; DEELNEMER DOCENT ------------ ------------ ALDERS SPIJKER BLAAK SPIJKER Academic Service, Den Haag 12

ADAMS MOLENAAR SCHOTTEN DE KONING SPIJKER BLAAK SPIJKER SPIJKER SPIJKER SMIT SMIT SMIT SMIT SMIT 3 Geef van iedere medewerker: naam, voorletters, en het jaarsalaris (inclusief toelage en commissie). select m.naam, m.voorl 2, 12 * (m.maandsal + s.toelage) 3 + nvl(m.comm,0) as jaarsalaris 4 from medewerkers m 5 join 6 schalen s 7 on (m.maandsal 8 between s.ondergrens 9 and s.bovengrens); NAAM VOORL JAARSALARIS ------------ ----- ----------- SMIT N 9600 JANSEN R 9600 ADAMS AA 13200 DE WAARD TF 16100 MARTENS P 17000 MOLENAAR TJA 16200 DEN DRAAIER JJ 19200 ALDERS JAM 20700 CLERCKX AB 31800 BLAAK R 36600 JANSEN JM 38100 SCHOTTEN SCJ 38400 SPIJKER MG 38400 DE KONING CC 66000 4 Geef van alle cursusuitvoeringen: de cursuscode, de begindatum, en het aantal inschrijvingen. Sorteer op begindatum. select cursus 2, begindatum 3, count(i.cursist) as inschrijvingen 4 from uitvoeringen u 5 left outer join 6 inschrijvingen i 7 using(cursus, begindatum) 8 group by cursus 9, begindatum 10 order by begindatum; CURS BEGINDATUM INSCHRIJVINGEN ---- ----------- -------------- S02 12-APR-1999 4 OAG 10-AUG-1999 3 Academic Service, Den Haag 13

S02 04-OCT-1999 3 JAV 13-DEC-1999 5 S02 13-DEC-1999 2 JAV 01-FEB-2000 3 XML 03-FEB-2000 2 PLS 11-SEP-2000 3 XML 18-SEP-2000 0 OAG 27-SEP-2000 1 ERM 15-JAN-2001 0 PRO 19-FEB-2001 0 RSO 24-FEB-2001 0 13 rows selected. NB: We hebben hier de outerjoin nodig om ook cursussen zonder inschrijvingen in het resultaat te krijgen. Denk er ook aan dat COUNT(*) op de derde regel het verkeerde resultaat zou opleveren! 5 Geef nu code, begindatum, en aantal inschrijvingen van alle cursusuitvoeringen in 1999 met minstens drie inschrijvingen. select cursus 2, begindatum 3, count(*) 4 from inschrijvingen 5 where extract(year from begindatum) = 1999 6 group by cursus 7, begindatum 8 having count(*) >= 3; CURSUS BEGINDATUM COUNT(*) ------ ----------- -------- JAV 13-DEC-1999 5 OAG 10-AUG-1999 3 S02 12-APR-1999 4 S02 04-OKT-1999 3 Omdat we toch niet geïnteresseerd zijn in uitvoeringen zonder deelnemers, kunnen we volstaan met de inschrijvingentabel. Dat zou anders zijn geweest als de vraag was geweest... met minder dan drie inschrijvingen ; nul is immers ook minder dan drie. 6 Geef de nummers van alle medewerkers die wèl ooit een cursus als docent hebben gegeven, maar nog nooit een cursus hebben gevolgd. select docent from uitvoeringen 2 minus 3 select cursist from inschrijvingen; DOCENT -------- 7369 Deze oplossing lijkt goed te zijn, maar ziet er voor een geoefend oog verdacht uit. Het resultaat bestaat namelijk niet uit een, maar uit twee rijen: set feedback 1 Academic Service, Den Haag 14

/ DOCENT -------- 7369 2 rows selected. We zouden dus expliciet null-waarden in de DOCENT-kolom ook nog moeten uitsluiten: select docent from uitvoeringen 2 where docent is not null 3 minus 4 select cursist from inschrijvingen; DOCENT -------- 7369 7 Welke medewerkers hebben een bepaalde cursus meer dan één keer gevolgd? select cursist,cursus 2 from inschrijvingen 3 group by cursist,cursus 4 having count(*) > 1 ; CURSIST CURSUS -------- ------ 7698 S02 7788 JAV 7902 S02 8 Geef van alle docenten: naam en voorletters, het aantal cursussen dat ze hebben gegeven, het totale aantal cursisten dat ze hebben opgeleid, en het gemiddelde evaluatiecijfer. Rond deze berekening af op één decimaal. select d.voorl, d.naam 2, count(distinct begindatum) cursussen 3, count(*) cursisten 4, round(avg(evaluatie),1) evaluatie 5 from medewerkers d 6, inschrijvingen i 7 join 8 uitvoeringen u 9 using(cursus, begindatum) 10 where d.mnr = u.docent 11 group by d.voorl, d.naam; VOORL NAAM CURSUSSEN CURSISTEN EVALUATIE ----- ------------ --------- --------- --------- N SMIT 3 7 4 AA ADAMS 1 3 4 JM JANSEN 2 8 4.3 Academic Service, Den Haag 15

MG SPIJKER 2 5 4 SCJ SCHOTTEN 1 3 NB: We gaan bij het tellen van de cursussen uit van de veronderstelling dat een docent nooit op dezelfde dag twee cursussen kan geven. 9 Geef naam en voorletters van alle trainers die ooit tijdens een algemene cursus (type ALG) hun eigen chef als cursist hebben gehad. select distinct 2 m.naam, m.voorl 3 from medewerkers m 4, cursussen c 5, uitvoeringen u 6, inschrijvingen i 7 where m.mnr = u.docent 8 and m.chef = i.cursist 9 and c.code = u.cursus 10 and u.cursus = i.cursus 11 and u.begindatum = i.begindatum 12 and c.type = 'ALG'; NAAM VOORL ------------ ----- SMIT N 10 Hebben we op een van de cursuslocaties op enig moment twee lokalen tegelijkertijd in gebruik gehad? select u1.locatie 2, u1.begindatum, u1.cursus 3, u2.begindatum, u2.cursus 4 from uitvoeringen u1 5, uitvoeringen u2 6, cursussen c 7 where u1.locatie = u2.locatie 8 and (u1.begindatum < u2.begindatum or 9 u1.cursus <> u2.cursus ) 10 and u1.cursus = c.code 11 and u2.begindatum between u1.begindatum 12 and u1.begindatum + c.lengte; LOCATIE BEGINDATUM CURSUS BEGINDATUM CURSUS -------------------- ----------- ------ ----------- ------ DE MEERN 01-FEB-2000 JAV 03-FEB-2000 XML We zoeken dus twee verschillende cursusuitvoeringen op dezelfde locatie, die elkaar overlappen. Het blijkt dat de Java-cursus van 1 februari 2000 in De Meern overlapt met de XML-cursus die twee dagen later start; de Java-cursus duurt namelijk vier dagen. 11 Geef een matrix-overzicht (voor elke afdeling een kolom, voor elke functie een rij) met in iedere cel het aantal medewerkers. In een query is het dynamisch bepalen van het aantal kolommen ondoenlijk; ga daarom uit van de afdelingsnummers 10, 20 en 30. Academic Service, Den Haag 16

select m.functie 2, sum(case m.afd when 10 then 1 else 0 end) as afd_10 3, sum(case m.afd when 20 then 1 else 0 end) as afd_20 4, sum(case m.afd when 30 then 1 else 0 end) as afd_30 5 from medewerkers m 6 group by m.functie; FUNCTIE AFD_10 AFD_20 AFD_30 ---------- -------- -------- -------- BOEKHOUDER 1 0 1 DIRECTEUR 1 0 0 MANAGER 1 1 1 TRAINER 0 4 0 VERKOPER 0 0 4 12 Zijn de twee queries in figuur 8.45 en 8.46 equivalent? Onderzoek de queries nader, en verklaar het eventuele verschil. Als we de FEEDBACK-instelling van SQL*Plus laag genoeg zetten, dan wordt het verschil meteen duidelijk: set feedback 1 select u.locatie from uitvoeringen u 2 MINUS 3 select a.locatie from afdelingen a; LOCATIE -------------------- MAASTRICHT 2 rows selected. select DISTINCT u.locatie 2 from uitvoeringen u 3 where u.locatie not in 4 (select a.locatie 5 from afdelingen a); LOCATIE -------------------- MAASTRICHT 1 row selected. Er bestaat een cursusuitvoering waarvan de locatie onbekend is, en zoals we inmiddels weten kunnen we niet voorzichtig genoeg zijn met null-waarden. In de eerste query komt die null-waarde in het resultaat voor, omdat hij er door de MINUS-operator niet wordt uitgehaald. Als de tweede query die bewuste rij aan het controleren is, wordt de WHERE-component: 3 where NULL not in ('LEIDEN','DE MEERN','UTRECHT','GRONINGEN') Deze conditie levert "onbekend" op, dus wordt de rij niet tot het resultaat toegelaten. Academic Service, Den Haag 17

Antwoorden opgaven paragraaf 9.8 1 Het komt vaak voor dat een (junior) docent een cursus eerst bij een collega volgt voordat hij hem zelf voor het eerst geeft. Voor welke docent/cursus-combinaties is dat gebeurd? Deze opgave is niet eenvoudig; hij kan op vele manieren worden opgelost. De hier gegeven oplossing, gebaseerd op gebruik van de EXISTS-operator, is als volgt te lezen: Zoek cursusuitvoeringen waarvoor geldt dat er voor de docent een eerdere deelname aan diezelfde cursus bestaat als cursist, èn waarvoor geldt dat het de eerste keer is dat de docent de cursus geeft. Deze laatste toevoeging is nodig, anders zouden ook de gevallen geven-volgen-geven verschijnen. select u.cursus, u.docent 2 from uitvoeringen u 3 where exists 4 (select i.* 5 from inschrijvingen i 6 where i.cursist = u.docent 7 and i.cursus = u.cursus 8 and i.begindatum < u.begindatum) 9 and not exists 10 (select eu.* 11 from uitvoeringen eu 12 where eu.cursus = u.cursus 13 and eu.docent = u.docent 14 and eu.begindatum < u.begindatum); CURSUS DOCENT ------ -------- JAV 7876 OAG 7902 2 Sterker nog: als de beginnende docent de cursus dan voor het eerst geeft, zit de docent waarvan hij eerder de kunst had afgekeken ter ondersteuning als deelnemer in het lokaal. Spoor dit soort cursus/junior/senior-combinaties op. Laten we deze opgave voor de variatie eens met een join oplossen: select u1.cursus 2, u1.docent as senior 3, u2.docent as junior 4 from uitvoeringen u1 5, inschrijvingen i1 6, uitvoeringen u2 7, inschrijvingen i2 8 where u1.cursus = i1.cursus -- join i1 met u1 9 and u1.begindatum = i1.begindatum 10 and u2.cursus = i2.cursus -- join i2 met u2 11 and u2.begindatum = i2.begindatum 12 and u1.cursus = u2.cursus -- u1 en u2 dezelfde cursus 13 and u1.begindatum < u2.begindatum -- maar u1 is eerder dan u2 14 and u1.docent = i2.cursist -- docent u1 volgt u2 15 and u2.docent = i1.cursist -- docent u2 volgt u1 16 ; CURSUS SENIOR JUNIOR ------ -------- -------- JAV 7566 7876 Academic Service, Den Haag 18

3 Welke medewerkers hebben nog nooit een cursus gegeven? In eerste instantie zouden we misschien verwachten dat beide hieronder gegeven oplossingen correct zijn. Let echter op de verschillende resultaten. Bepaal zelf wat de juiste oplossing is. select m.* 2 from medewerkers m 3 where m.mnr not in (select u.docent 4 from uitvoeringen u); no rows selected select m.* 2 from medewerkers m 3 where not exists (select u.docent 4 from uitvoeringen u 5 where u.docent = m.mnr); MNR NAAM VOORL FUNCTIE CHEF GBDATUM MAANDSAL COMM AFD ----- ------------ ----- ---------- ----- ----------- -------- ----- --- 7499 ALDERS JAM VERKOPER 7698 20-FEB-1961 1600 300 30 7521 DE WAARD TF VERKOPER 7698 22-FEB-1962 1250 500 30 7654 MARTENS P VERKOPER 7698 28-SEP-1956 1250 1400 30 7698 BLAAK R MANAGER 7839 01-NOV-1963 2850 30 7782 CLERCKX AB MANAGER 7839 09-JUN-1965 2450 10 7839 DE KONING CC DIRECTEUR 17-NOV-1952 5000 10 7844 DEN DRAAIER JJ VERKOPER 7698 28-SEP-1968 1500 0 30 7900 JANSEN R BOEKHOUDER 7698 03-DEC-1969 800 30 7934 MOLENAAR TJA BOEKHOUDER 7782 23-JAN-1962 1300 10 9 rows selected. Voor beide oplossingen is wat te zeggen. Het is namelijk zo dat er cursus-uitvoeringen voorkomen met een null-waarde in de DOCENT-kolom. Als we deze null-waarden opvatten als docent onbekend dan kunnen we dus nooit met zekerheid zeggen dat een bepaalde medewerker nog nooit een cursus heeft gegeven. De tweede query behandelt de null-waarden duidelijk anders; we moeten dus onze vraag iets preciezer formuleren om te kunnen bepalen welke oplossing gewenst is. 4 Welke werknemers hebben alle bouwcursussen (type BLD) gevolgd? Ze hebben namelijk recht op korting. Dit is geen gemakkelijke opgave. We geven hier twee oplossingen. select m.mnr, m.naam, m.voorl 2 from medewerkers m 3 where not exists 4 (select c.* 5 from cursussen c 6 where c.type = 'BLD' 7 and not exists 8 (select i.* 9 from inschrijvingen i 10 where i.cursus = c.code 11 and i.cursist = m.mnr 12 ) 13 ); Academic Service, Den Haag 19

MNR NAAM VOORL ----- ------------ ----- 7499 ALDERS JAM Alternatieve oplossing, met een GROUP BY: select m.mnr, m.naam, m.voorl 2 from medewerkers m 3, cursussen c 4, inschrijvingen i 5 where i.cursus = c.code 6 and i.cursist = m.mnr 7 and c.type = 'BLD' 8 group by m.mnr, m.naam, m.voorl 9 having count(distinct i.cursus)=(select count(*) 10 from cursussen 11 where type='bld'); MNR NAAM VOORL ----- ------------ ----- 7499 ALDERS JAM 5 Wie hebben (tenminste) dezelfde cursussen gevolgd als medewerker 7788 gevolgd heeft? Dit is ook geen gemakkelijke opgave. De hier gegeven constructie met de MINUS-operator en een gecorreleerde subquery is elegant. Let overigens op de plaats van de ontkenning. De oplossing kan het beste als volgt worden gelezen: Geef alle medewerkers (behalve 7788 zelf) waarvoor geldt dat er géén cursus is die 7788 wèl heeft gevolgd, en zij niet. select m.naam,m.voorl 2 from medewerkers m 3 where m.mnr <> 7788 4 and not exists 5 (select i1.cursus 6 from inschrijvingen i1 7 where i1.cursist = 7788 8 MINUS 9 select i2.cursus 10 from inschrijvingen i2 11 where i2.cursist = m.mnr); NAAM VOORL ------------ ----- ALDERS JAM BLAAK R DE KONING CC ADAMS AA Merk overigens de treffende gelijkenis op van deze opgave en de vorige opgave; het zijn beide voorbeelden uit de categorie deelverzamelingproblemen. De twee gegeven oplossingsmethoden zijn dan ook uitwisselbaar. 6 Geef de gegevens van alle medewerkers waarvan het maandsalaris en de commissie overeenkomen met het maandsalaris en de commissie van (minstens) een medewerker van Academic Service, Den Haag 20