Løsningsforlag for oblig 1, databaser 2010 Oppgave 1 a) Hvilke supernøkler finnes i de to tabellene? Tabellen klasse har følgende supernøkler: (klasseid, klassebetegnelse) (klasseid) Tabellen renndeltager har følgende supernøkler: (startnr, fornavn, etternavn, personnr, klasseid) (startnr, fornavn, etternavn, personnr) (startnr, fornavn, etternavn) (startnr, fornavn) (startnr, etternavn) (startnr, personnr) (startnr, klasseid) (startnr) (fornavn, etternavn, personnr, klasseid) (fornavn, etternavn, personnr) (fornavn, personnr) (personnr) ++ så lenge de fortsatt er unike (dvs inneholder en potensiell kandidatnøkkel) kan man holde på nærmest i det uendelige b) Hvilke kandidatnøkler finnes i de to tabellene? Tabellen klasse har følgende kandidatnøkler: (klasseid) Tabellen renndeltager har følgende kandidatnøkler: (startnr) (personnr)
c) Hvilke primærnøkler finnes i de to tabellene? Primærnøkkel velges utfra de tilgjengelige kandidatnøklene. Tabellen klasse har primærnøkkelen (klasseid) For tabellen renndeltager er det like riktig å si at primærnøkkelen er (startnr) som at den er (personnr), men det er viktig å merke seg at begge ikke kan være primærnøkkel samtidig. d) Hvilke fremmednøkler finnes i de to tabellene? I denne oppgaven er det bare en fremmednøkkel, og dette ligger i tabellen renndeltager: (klasseid) e) Hvilke entitetstyper finnes? klasse og renndeltager f) Hvilke entiteter finnes i de to tabellene? I tabellen klasse finnes følgende entiteter: 1, 'K20-25' 2, 'K25-30' 3, 'K20-25' 4, 'K25-30' I tabellen renndeltager finnes følgende entiteter: 1, 'Anne', 'Jensen', '01017011111', 1 2, 'Anders', 'Olsen', '01017022222', 3 3, 'Per', 'Hansen', '01017033333', 3 4, 'Kurt', 'Iversen', '01017044444, 4 5, 'Eva', 'Adamsen', '01017055555', 1 6, 'Inger', 'Jensen', '01017066666', 2 7, 'Per', 'Olsen', '01017077777', 4 g) Hvilke attributter har de to tabellene?
I tabellen klasse finnes følgende attributter: klasseid klassebetegnelse I tabellen renndeltager finnes følgende attributter: startnr fornavn etternavn personnr klasseid Oppgave 2 a) Skole Skoleansatt Elev Klasse Poststed skolenavn skole elev_id skole postnr adresse ansattnr fornavn klasse poststed postnr fornavn etternavn klassestyrer telefonnr etternavn skole rektor kontornr klasse interntelefonnr b) Dataene kan kobles sammen ved hjelp av fremmednøkler: postnr i Skole til postnr i Poststed (skolenavn, rektor) i Skole til (skole, ansattnr) i Skoleansatt skole i Skoleansatt til skolenavn i Skole (skole, klasse) i Elev til (skole, klasse) i Klasse skole i Klasse til skolenavn i Skole (skole, klassestyrer) i Klasse til (skole, ansattnr) Merk! En skole har gjerne mer enn bare en rektor og flere lærere. I et "virkelig" system ville det vært hensiktsmessig å ha med en tabell AnsattType der for eksempel rektor, inspektør, rådgiver, lærer osv kan lagres. Hvis en ansatt kan ha flere roller (for eksempel både lærer og rektor), må man ha en egen tabell for å lagre ansattforholdene.
Oppgave 3 a) S U O = {1,2,3,4,5,6,7,8,9,10,'a','b','c','d','e','f','g','h','i'} U {2,4,6,8,10,12,14,16,18,20,'c','g','i'} = {1,2,3,4,5,6,7,8,9,10,'a','b','c','d','e','f','g','h','i',12,14,16,18,20} b) S U L = {1,2,3,4,5,6,7,8,9,10,'a','b','c','d','e','f','g','h','i'} U {1,3,5,7,9,11,13,15,17,19,'a','e','i','o','u','y','æ','ø','å'} = {1,2,3,4,5,6,7,8,9,10,'a','b','c','d','e','f','g','h','i',11,13,15,17,19,'o','u','y','æ','ø','å'} c) S O = {1,2,3,4,5,6,7,8,9,10,'a','b','c','d','e','f','g','h','i'} {2,4,6,8,10,12,14,16,18,20,'c','g','i'} = {2,4,6,8,10,'c','g','i'} d) L A = {1,3,5,7,9,11,13,15,17,19,'a','e','i','o','u','y','æ','ø','å'} {10,11,12,13,14,15,16,17,18,19,20} = {11,13,15,17,19} e) A L = {10,11,12,13,14,15,16,17,18,19,20} {1,3,5,7,9,11,13,15,17,19,'a','e','i','o','u','y','æ','ø','å'} = {11,13,15,17,19} f) L \ S = {1,3,5,7,9,11,13,15,17,19,'a','e','i','o','u','y','æ','ø','å'} \ {1,2,3,4,5,6,7,8,9,10,'a','b','c','d','e','f','g','h','i'} = {11,13,15,17,19,'o','u','y','æ','ø','å'} g) S \ L = {1,2,3,4,5,6,7,8,9,10,'a','b','c','d','e','f','g','h','i'} \ {1,3,5,7,9,11,13,15,17,19,'a','e','i','o','u','y','æ','ø','å'} = {2,4,6,8,10,'b','c','d','f','g','h'} h) (S L) \ O = ({1,2,3,4,5,6,7,8,9,10,'a','b','c','d','e','f','g','h','i'} {1,3,5,7,9,11,13,15,17,19,'a','e','i','o','u','y','æ','ø','å'}) \ {2,4,6,8,10,12,14,16,18,20,'c','g','i'} = {1,3,5,7,9,'a','e','i'} \ {2,4,6,8,10,12,14,16,18,20,'c','g','i'} = {1,3,5,7,9,'a','e'}
Oppgave 4 a)
b)
c) Oppgave 5 a) Dette skal gå uten feilmeldinger b) Dette skal gå uten feilmeldinger c) SELECT * FROM sykehus; Antall rader: 16 Antall kolonner: 7
forkortelse navn region adresse postnr telefon_sentralbord ant_ansatte -------------+---------------------------------+------------------+------------------+--------+---------------------+------------- AHUS Akershus universitetssykehus HF Helse Sør-Øst Sykehusgata 1 0052 22 445533 12358 OSLO Oslo universitetssykehus HF Helse Sør-Øst Sykehusgata 2 0043 22 785465 7623 SIV Sykehuset i Vestfold HF Helse Sør-Øst Sykehusgata 3 2054 31 487854 4657 SIHF Sykehuset Innlandet HF Helse Sør-Øst Sykehusgata 4 3187 25 005478 2578 STHF Sykehuset Telemark HF Helse Sør-Øst Sykehusveien 5 3289 26 478952 687 d) SELECT navn, region FROM sykehus; Antall rader: 16 Antall kolonner: 2 navn region ---------------------------------+------------------ Akershus universitetssykehus HF Helse Sør-Øst Oslo universitetssykehus HF Helse Sør-Øst Sykehuset i Vestfold HF Helse Sør-Øst Sykehuset Innlandet HF Helse Sør-Øst Sykehuset Telemark HF Helse Sør-Øst e) SELECT DISTINCT region FROM sykehus; NB! Her skal det IKKE brukes GROUP BY! Antall rader: 4 Antall kolonner: 1 region ------------------ Helse Midt-Norge Helse Nord Helse Sør-Øst Helse Vest f) SELECT navn FROM sykehus WHERE region = 'Helse Vest'; Antall rader: 5 Antall kolonner: 1
navn -------------------------------- Haukeland universitetssjukehus Odda sjukehus Stavanger universitetssjukehus Førde Sentralsjukehus Lærdal Sjukehus g) SELECT * FROM sykehus WHERE ant_ansatte <> 2845; eller SELECT * FROM sykehus WHERE ant_ansatte!= 2845; Antall rader: 15 Antall kolonner: 7 postnr telefon_sentralbord ant_ansatte -------------+---------------------------------+------------------+------------------+--------+---------------------+------------- AHUS Akershus universitetssykehus HF Helse Sør-Øst Sykehusgata 1 0052 22 445533 12358 OSLO Oslo universitetssykehus HF Helse Sør-Øst Sykehusgata 2 0043 22 785465 7623 SIV Sykehuset i Vestfold HF Helse Sør-Øst Sykehusgata 3 2054 31 487854 4657 SIHF Sykehuset Innlandet HF Helse Sør-Øst Sykehusgata 4 3187 25 005478 2578 STHF Sykehuset Telemark HF Helse Sør-Øst Sykehusveien 5 3289 26 478952 687 h) SELECT navn, region, adresse FROM sykehus WHERE adresse LIKE 'Sykehusveien%'; Antall rader: 6 Antall kolonner: 3
navn region adresse --------------------------------+------------------+------------------ Sykehuset Telemark HF Helse Sør-Øst Sykehusveien 5 Sykehuset Østfold HF Helse Sør-Øst Sykehusveien 6 Sørlandet sykehus Helse Sør-Øst Sykehusveien 7 Stavanger universitetssjukehus Helse Vest Sykehusveien 20 Sykehuset Namsos Helse Midt-Norge Sykehusveien 8 i) SELECT navn, region, adresse FROM sykehus WHERE adresse NOT LIKE 'Sykehusveien%'; eller SELECT navn, region, adresse FROM sykehus WHERE NOT adresse LIKE 'Sykehusveien%'; Antall rader: 10 Antall kolonner: 3 navn region adresse ---------------------------------+------------------+------------------ Akershus universitetssykehus HF Helse Sør-Øst Sykehusgata 1 Oslo universitetssykehus HF Helse Sør-Øst Sykehusgata 2 Sykehuset i Vestfold HF Helse Sør-Øst Sykehusgata 3 Sykehuset Innlandet HF Helse Sør-Øst Sykehusgata 4 Haukeland universitetssjukehus Helse Vest Sjukehusvegen 65 Oppgave 6 a) Feltet navn kan splittes opp i følgende felter: fornavn, etternavn fornavn, mellomnavn, etternavn b) navn kan splittes opp i fornavn og etternavn, eller i fornavn, mellomnavn og etternavn taxi kan splittes opp i Merke (Ford), modell (Mondeo 2.0D) og årsmodell (1999) turdatoogtid kan splittes opp i turtid_fra og turtid_til, evt kan man splitte i fire slik at man i tillegg får turdato_fra og turdato_til
turstartsted og turstoppsted kan stå som det er, eller splittes opp i gatenavn og husnummer c) CREATE TABLE eier( eierid INT NOT NULL, navn VARCHAR(50), PRIMARY KEY(eierid) ); CREATE TABLE video( videoid INT NOT NULL, navn VARCHAR(50), sjanger VARCHAR(25), PRIMARY KEY(videoid) ); CREATE TABLE videoeierskap( eierid INT NOT NULL, videoid INT NOT NULL, PRIMARY KEY(eierid, videoid), FOREIGN KEY (eierid) references eier, FOREIGN KEY (videoid) references video ); d) INSERT INTO eier VALUES(1, 'Per'); INSERT INTO eier VALUES(2, 'Anne'); INSERT INTO eier VALUES(3, 'Ola'); INSERT INTO eier VALUES(4, 'Kjersti'); INSERT INTO video VALUES(1, 'Dirty Dancing', 'Familie'); INSERT INTO video VALUES(2, 'Rambo', 'Action'); INSERT INTO video VALUES(3, 'Politiskolen 1', 'Komedie'); INSERT INTO videoeierskap VALUES(1, 1);
INSERT INTO videoeierskap VALUES(1, 2); INSERT INTO videoeierskap VALUES(2, 3); INSERT INTO videoeierskap VALUES(3, 2); INSERT INTO videoeierskap VALUES(4, 1); e) UPDATE video SET sjanger = 'Romantisk komedie' WHERE navn = 'Dirty Dancing'; f) Problemer som kan oppstå når to personer skal bytte filmer: Når man har kjørt den første delen av oppdateringen, så vil den ene personen eie begges filmer, og man har ikke lenger noen oversikt over hvem som eide hva i utgangspunktet. Forslag til UPDATE-setninger: UPDATE videoeierskap SET eierid = 2 WHERE eierid = 3; UPDATE videoeierskap SET eierid = 3 WHERE videoid = 3 AND eierid = 2; Oppgave 7 a) Dette skal gå greit uten feilmeldinger, slik: For MySQL: mysql -u elinkaan_v11 -p -D elinkaan_v11 \. landskoder-create.sql \. mysql-24timerlop07-10-create.sql For PostgresSQL: psql -f landskoder-create.sql -d elinkaan_v11 -U elinkaan psql -f psql-24timerlop07-10-create.sql -d elinkaan_v11 -U elinkaan b) Dette skal gå greit uten feilmeldinger, slik: For MySQL: mysql -u elinkaan_v11 -p -D elinkaan_v11 \. mysql-landskoder-utf8.sql \. mysql-24timerlop07-10-utf8.sql
For PostgreSQL: psql -f psql-landskoder-utf8.sql -d elinkaan_v11 -U elinkaan psql -f psql-24timerlop07-10-utf8.sql -d elinkaan_v11 -U elinkaan c) SELECT COUNT(*) ; Antall rader: 1 Antall kolonner: 1 count ------- 16221 d) SELECT distanse_km, fornavn, etternavn, dato, arrsted, arrland WHERE distanse_km BETWEEN 200 AND 210; Antall rader: 594 Antall kolonner: 6 distanse_km fornavn etternavn dato arrsted arrland -------------+-----------------------+----------------------------+------------+--------------------------------+--------- 206.18 Angel Marcos de la Mata Garcia 2007-12-16 Barcelona ESP 206.071 Maurice Chenais 2007-05-06 Sene FRA 206.059 Olivier Lhuillery 2007-10-07 Arcueil FRA 206 Vasilij Emanov 2007-09-02 St. Petersburg RUS 205.997 Christian Fournier 2007-04-08 Montigny-en-Gohelle FRA e) SELECT distanse_km, fornavn, etternavn, dato, arrsted, arrland WHERE distanse_km >= 200 AND distanse_km <= 210; Antall rader: 594 Antall kolonner: 6
distanse_km fornavn etternavn dato arrsted arrland -------------+-----------------------+----------------------------+------------+--------------------------------+--------- 206.18 Angel Marcos de la Mata Garcia 2007-12-16 Barcelona ESP 206.071 Maurice Chenais 2007-05-06 Sene FRA 206.059 Olivier Lhuillery 2007-10-07 Arcueil FRA 206 Vasilij Emanov 2007-09-02 St. Petersburg RUS 205.997 Christian Fournier 2007-04-08 Montigny-en-Gohelle FRA f) SELECT DISTINCT fornavn, etternavn WHERE nasjonalitet IN (SELECT landskode FROM landskode WHERE landsnavn = 'Norge') ORDER BY etternavn ASC; (i dette tilfellet kan vi evt bruke = istedenfor IN siden vi vet at subquery-en kun returnerer ett svar, men i teorien kunne et landsnavn hatt to landskoder) eller SELECT DISTINCT fornavn, etternavn WHERE nasjonalitet = 'NOR' ORDER BY etternavn ASC; eller SELECT DISTINCT fornavn, etternavn, landskode WHERE nasjonalitet = landskode AND landsnavn = 'Norge' ORDER BY etternavn ASC; Antall rader: 73 Antall kolonner: 2 fornavn etternavn -----------------+--------------- Henrik Aasbø Ulf Aas Hansen Øistein Ackenhausen Mujtaba Ahmad
Rune Akselsen g) SELECT DISTINCT fornavn, etternavn, fodt_aar WHERE nasjonalitet IN (SELECT landskode FROM landskode WHERE landsnavn = 'USA') ORDER BY fornavn DESC; eller SELECT DISTINCT fornavn, etternavn, fodt_aar WHERE nasjonalitet = 'USA' ORDER BY fornavn DESC; eller SELECT DISTINCT fornavn, etternavn, fodt_aar, landskode WHERE nasjonalitet = landskode AND landsnavn = 'USA' ORDER BY fornavn DESC; Antall rader: 1274 Antall kolonner: 3 fornavn etternavn fodt_aar ----------------+-------------------+---------- Zeb Gray Zachary Lewis 1977 Zach Gingerich 1979 Zach Pierce 1973 Yen Nguyen 1962 h) SELECT fornavn, etternavn, nasjonalitet, distanse_km * 1000 AS "Distanse i meter" WHERE
EXTRACT(year FROM dato) = 2010 AND distanse_km = (SELECT MAX(distanse_km) WHERE EXTRACT(year FROM dato) = 2010 ); evt. kan også funksjonen date_part brukes i PostgreSQL, slik: SELECT fornavn, etternavn, nasjonalitet, distanse_km * 1000 AS "Distanse i meter" WHERE DATE_PART('year', dato) = 2010 AND distanse_km = (SELECT MAX(distanse_km) WHERE DATE_PART('year', dato) = 2010 ); Antall rader: 1 Antall kolonner: 4 fornavn etternavn nasjonalitet Distanse i meter ---------+-----------+--------------+------------------ Shingo Inoue JPN 273708 i) SELECT landsnavn FROM landskode WHERE landsnavn NOT LIKE 'S%'; eller SELECT landsnavn FROM landskode WHERE NOT landsnavn LIKE 'S%'; Antall rader: 53 Antall kolonner: 1 landsnavn -------------------- Korea Russland Frankrike Italia Tjekkia
j) SELECT fornavn, etternavn WHERE nasjonalitet = 'MLI' OR nasjonalitet = 'RSA' OR nasjonalitet = 'MEX'; Antall rader: 15 Antall kolonner: 2 fornavn etternavn ------------------+-------------------- Juan Antonio Bravo Ramirez Eric Wright Jesus Gonzalez Hernandez Bougary (Doudou) Coulibaly Jose Roberto Espino Balderas k) SELECT fornavn, etternavn WHERE nasjonalitet IN( SELECT landskode FROM landskode WHERE landskode = 'MLI' OR landskode = 'RSA' OR landskode = 'MEX'); Antall rader: 15 Antall kolonner: 2 fornavn etternavn ------------------+-------------------- Juan Antonio Bravo Ramirez Eric Wright Jesus Gonzalez Hernandez Bougary (Doudou) Coulibaly Jose Roberto Espino Balderas l) = brukes for å sammeligne faste tekststrenger (for eksempel 'Norge'), mens LIKE brukes for å sammenligne tekststrenger der deler av teksten er ukjent (for eksempel 'Nor%' for ord som starter med Nor og der det kommer noe mer etterpå.) m) MySQL: \h, \? og help kan brukes om hverandre i MySQL alle disse tre brukes for å få hjelp med mysql-operasjoner (for eksempel hvordan bytte database, endre passord, liste tabeller osv)
help contents brukes for å skaffe en oversikt over hva man kan spørre om (for eksempel help comparison operators) PostgreSQL: \h brukes for å få opp hjelp med SQL-kommandoer \? brukes for å få hjelp med psql-operasjoner (for eksempel hvordan bytte database, endre passord, liste tabeller osv) n) MySQL: SHOW tables; PostgreSQL: \dt o) SELECT DISTINCT nasjonalitet WHERE distanse_km > 200 AND EXTRACT(year FROM dato) = 2007 ORDER BY nasjonalitet ASC; Antall rader: 32 Antall kolonner: 1 nasjonalitet -------------- ARG AUS AUT BEL BRA p) SELECT DISTINCT fornavn, etternavn, nasjonalitet WHERE fodt_aar IS NULL; Antall rader: 925 Antall kolonner: 3
fornavn etternavn nasjonalitet ---------------------+----------------------------+-------------- Adair Goncalvez Silva BRA Adao Miranda da Silva BRA Adolfo Eguilar ESP Adrian McDermott GBR Adriano da Costa Antunes BRA q) SELECT COUNT(*) WHERE fodt_aar IS NOT NULL; eller SELECT COUNT(*) WHERE NOT fodt_aar IS NULL; Antall rader: 1 Antall kolonner: 1 count ------- 15014 Oppgave 8 a) Feil: Det mangler informasjon om hvilken tabell data skal hentes fra Riktig setning: SELECT fornavn WHERE nasjonalitet = NOR ; b) Feil: Det mangler semikolon på slutten av spørringen Riktig setning: SELECT etternavn WHERE fornavn = Per ;
c) Feil: NOT kan ikke stå alene foran en subquery. Det riktige er NOT IN. I tillegg er det en feil inne i subqueryen. Man kan ikke ha et uttrykk a'la x=3 inne i en SELECT; til dette formålet har man WHERE. Man kan heller ikke bruke = når man skal teste på et uttrykk (til forskjell fra en fast tekststreng); da bruker man LIKE. Ukjent tegn i en tekststreng er heller ikke *, men %. Riktig setning: SELECT fornavn, etternavn WHERE nasjonalitet NOT IN (SELECT landskode FROM landskode WHERE landsnavn LIKE 'K%'); d) Feil: Man kan ikke bruke AND når man skal liste opp hvilke kolonner som skal være med i en SELECT I tillegg finnes det ikke noen kolonne som heter arrnavn. Er det landet man er ute etter kanskje? Riktig setning: SELECT arrsted, arrland ; e) SELECT AVG(nasjonalitet) ; Feil: Man kan ikke beregne gjennomsnitt av en tekststreng. Riktig setning: Her er det umulig å vite hva som egentlig var ønskelig, så det finnes ingen riktig setning. Kort oppsummert Man skal ikke bruke LIKE til annet enn testing av tekststrenger! For datoer, tall og andre udde datatyper har man egne funksjoner for testing av deler av verdien LIKE og = skal ikke brukes om hverandre. = brukes ved testing av faste strenger, for eksempel 'Per', mens LIKE brukes der deler av strengen er ukjent, også kjent som regulæruttrykk, for eksempel 'Pe%'. Det motsatte av LIKE og = er NOT LIKE og <> (evt!=). DISTINCT og GROUP BY er ikke det samme! DISTINCT brukes når man skal returnere unike rader, for eksempel i tilfeller der hvert fornavn kun skal listes opp en gang. GROUP BY brukes kun i forbindelse med agreggeringsfunksjoner som MAX, MIN, COUNT,... Når vi skal teste på om en verdi er NULL skal vi bruke uttrykket IS NULL, aldri = NULL eller LIKE NULL.