För att förenkla programmeringen av tillämpningsprogrammen har vi infört enkla numeriska primärnycklar som databasinterna "radnummer" i tabellerna arbetar och diagnos. Alternativt kunde man använt kombinationen av personal och avdelning som primärnyckel i tabellen arbetar, och kombinationen av patient och sjukdom som primärnyckel i tabellen diagnoser. I lösningen ovan är de i stället alternativnycklar.
Alla entitetstyperna hade redan enkla numeriska nycklar, så vi inför inga särskilda databasinterna nycklar för dem. (Vi antar då att numren på patienter och personal inte är vanliga svenska personnummer, som normalt måste lagras som textsträngar och inte som tal.)
SQL-kommandon för att provköra:
create unique sequence avdelningsnummer; create table avdelningar (nummer integer default next_value of avdelningsnummer not null primary key, namn char(10) unique); create unique sequence personalnummer; create table personal (nummer integer default next_value of personalnummer not null primary key, namn char(10), typ char(10)); create unique sequence arbetsnummer; create table arbetar (nummer integer default next_value of arbetsnummer not null primary key, personal integer references personal(nummer), avdelning integer references avdelningar(nummer), unique(personal, avdelning)); create unique sequence patientnummer; create table patienter (nummer integer default next_value of patientnummer not null primary key, namn char(10), avdelning integer references avdelning(nummer)); create unique sequence sjukdomsnummer; create table sjukdomar (nummer integer default next_value of sjukdomsnummer not null primary key, namn char(10) unique); create unique sequence diagnosnummer; create table diagnoser (nummer integer default next_value of diagnosnummer not null primary key, patient integer references patienter(nummer), sjukdom integer references sjukdomar(nummer), unique(patient, sjukdom)); insert into avdelningar(namn) values('IVA'); insert into avdelningar(namn) values('Medicin'); insert into avdelningar(namn) values('Ortopedi'); insert into avdelningar(namn) values('Kirurgi'); insert into personal(namn, typ) values('Anna Ek', 'läkare'); insert into personal(namn, typ) values('Bo Ek', 'ssk'); insert into personal(namn, typ) values('Cesar Ek', 'tekniker'); insert into personal(namn, typ) values('Donna Ek', 'läkare'); insert into personal(namn, typ) values('Erik Ek', 'usk'); insert into personal(namn, typ) values('Filip Ek', 'städare'); insert into personal(namn, typ) values('Gunilla Ek', 'väktare'); insert into personal(namn, typ) values('Hans Ek', 'läkare'); insert into personal(namn, typ) values('Inga Ek', 'läkare'); insert into personal(namn, typ) values('Jörn Ek', 'läkare'); insert into arbetar(personal, avdelning) values (1, 3); insert into arbetar(personal, avdelning) values (2, 3); insert into arbetar(personal, avdelning) values (3, 3); insert into arbetar(personal, avdelning) values (4, 3); insert into arbetar(personal, avdelning) values (5, 3); insert into arbetar(personal, avdelning) values (6, 3); insert into arbetar(personal, avdelning) values (7, 3); insert into arbetar(personal, avdelning) values (8, 3); insert into arbetar(personal, avdelning) values (9, 3); insert into arbetar(personal, avdelning) values (1, 4); insert into arbetar(personal, avdelning) values (2, 4); insert into arbetar(personal, avdelning) values (3, 4); insert into arbetar(personal, avdelning) values (4, 4); insert into patienter(namn, avdelning) values('Anna Berg', null); insert into patienter(namn, avdelning) values('Bo Berg', 1); insert into patienter(namn, avdelning) values('Cesar Berg', 2); insert into patienter(namn, avdelning) values('Donna Berg', 3); insert into patienter(namn, avdelning) values('Erik Berg', null); insert into patienter(namn, avdelning) values('Filip Berg', 1); insert into patienter(namn, avdelning) values('Gun Berg', 1); insert into patienter(namn, avdelning) values('Hans Berg', 1); insert into patienter(namn, avdelning) values('Inga Berg', 2); insert into patienter(namn, avdelning) values('Jörn Berg', 3); insert into sjukdomar(namn) values('värk'); insert into sjukdomar(namn) values('smärtor'); insert into sjukdomar(namn) values('galenskap'); insert into sjukdomar(namn) values('pest'); insert into sjukdomar(namn) values('kolera'); insert into diagnoser(patient, sjukdom) values (1, 5); insert into diagnoser(patient, sjukdom) values (2, 5); insert into diagnoser(patient, sjukdom) values (3, 5); insert into diagnoser(patient, sjukdom) values (4, 5); insert into diagnoser(patient, sjukdom) values (5, 5); insert into diagnoser(patient, sjukdom) values (6, 5); insert into diagnoser(patient, sjukdom) values (7, 5); insert into diagnoser(patient, sjukdom) values (1, 1); insert into diagnoser(patient, sjukdom) values (2, 1); insert into diagnoser(patient, sjukdom) values (3, 1); insert into diagnoser(patient, sjukdom) values (4, 1); insert into diagnoser(patient, sjukdom) values (1, 4); insert into diagnoser(patient, sjukdom) values (2, 4); insert into diagnoser(patient, sjukdom) values (3, 4); insert into diagnoser(patient, sjukdom) values (6, 4); insert into diagnoser(patient, sjukdom) values (7, 4); select * from avdelningar; select * from personal; select * from arbetar; select * from patienter; select * from sjukdomar; select * from diagnoser;
En alternativ lösning:select patienter.nummer, patienter.namn from patienter, avdelningar where patienter.avdelning = avdelningar.nummer and avdelningar.namn = 'Ortopedi';
select nummer, namn from patienter where avdelning in (select nummer from avdelningar where namn = 'Ortopedi');
b) (2p) Vilka patienter har pest?
En alternativ lösning:select patienter.nummer, patienter.namn from patienter, diagnoser, sjukdomar where patienter.nummer = diagnoser.patient and diagnoser.sjukdom = sjukdomar.nummer and sjukdomar.namn = 'pest';
select nummer, namn from patienter where nummer in (select patient from diagnoser where sjukdom in (select nummer from sjukdomar where namn = 'pest'));
c) (1p) Vilka patienter vårdas inte på någon avdelning?
Notera att följande fråga (som också skulle kunna utläsas "vilka patienter vårdas på en avdelning som inte finns") ger fel svar, eftersom alla jämförelser med null (utom is null) blir falska:select nummer, namn from patienter where avdelning is null;
select nummer, namn from patienter where avdelning not in (select nummer from avdelning);
d) (1p) Vilka patienter har (såvitt vi vet) inga sjukdomar?
select nummer, namn from patienter where nummer not in (select patient from diagnoser);
e) (1p) Hur många personal av varje typ (som till exempel läkare, sjuksköterskor och tekniker) finns det?
select typ, count(*) from personal group by typ;
f) (3p) Vilken sjukdom är vanligast?
create view antal_diagnoser as select sjukdomar.nummer, sjukdomar.namn, count(*) as antal from sjukdomar, diagnoser where sjukdomar.nummer = diagnoser.sjukdom group by sjukdomar.nummer, sjukdomar.namn; select * from antal_diagnoser; select namn from antal_diagnoser where antal = (select max(antal) from antal_diagnoser);
g) (3p) Pest är smittsamt! Vilka patienter har inte pest (än), men vårdas på samma avdelning som någon patient som har pest?
create view patienter_med_pest as select diagnoser.patient as nummer from diagnoser, sjukdomar where diagnoser.sjukdom = sjukdomar.nummer and sjukdomar.namn = 'pest'; create view avdelningar_med_pest as select avdelning as nummer from patienter where nummer in (select nummer from patienter_med_pest); select distinct nummer, namn from patienter where nummer not in (select nummer from patienter_med_pest) and avdelning in (select nummer from avdelningar_med_pest);
Skapa index på:
Några kolumner som man antagligen inte bör skapa index på:
SQL-kommandon för att provköra:
create index pavdelning on patienter(avdelning); create index pnummer on patienter(nummer); create index dpatient on diagnoser(patient); create index dsjukdom on diagnoser(sjukdom); create index snummer on sjukdomar(nummer); create index snamn on sjukdomar(namn);
b) (1p)
Ett index är en datastruktur som gör att det går snabbt att hitta rader i en tabell om man känner till värdet på den indexerade kolumnen.
Tabeller, med primärnycklarna är understrukna:
SQL-kommandon för att provköra:
create unique sequence personaltypsnummer; create table personaltyp (nummer integer default next_value of personaltypsnummer not null primary key, namn char(10) unique); create unique sequence personal2nummer; create table personal2 (nummer integer default next_value of personal2nummer not null primary key, namn char(10), typ integer not null references personaltyp(nummer)); insert into personaltyp(namn) values('läkare'); insert into personaltyp(namn) values('ssk'); insert into personaltyp(namn) values('usk'); insert into personaltyp(namn) values('tekniker'); insert into personaltyp(namn) values('städare'); insert into personaltyp(namn) values('väktare'); insert into personaltyp(namn) values('fältskär'); insert into personaltyp(namn) values('homeopat'); insert into personal2(namn, typ) values('Anna Ek', 1); insert into personal2(namn, typ) values('Bo Ek', 2); insert into personal2(namn, typ) values('Cesar Ek', 4); insert into personal2(namn, typ) values('Donna Ek', 1); insert into personal2(namn, typ) values('Erik Ek', 3); insert into personal2(namn, typ) values('Filip Ek', 5); insert into personal2(namn, typ) values('Gunilla Ek', 6); insert into personal2(namn, typ) values('Hans Ek', 1); insert into personal2(namn, typ) values('Inga Ek', 1); insert into personal2(namn, typ) values('Jörn Ek', 1);
b) (3p)
select personaltyp.namn, count(personal2.nummer) from personaltyp left outer join personal2 on personaltyp.nummer = personal2.typ group by personaltyp.namn;
Kommentar: coalesce behövs inte. count ger noll och inte null om den inte hittar några rader.
Tabellen uppfyller 1NF och 2NF, men inte 3NF och BCNF.
b) (2p)
Tre problem:
c) (1p)
Ett fullständigt funktionellt beroende är ett funktionellt beroende där determinanten är minimal, dvs där det inte går att ta bort några kolumner ur determinanten om det fortfarande ska vara ett funktionellt beroende. Exempel:
a) XML är ett sätt att göra databasen mer aktiv, genom att man skriver XML-kod som sen körs automatiskt när vissa villkor är uppfyllda i databasen.
Fel. Det där handlar nog om triggers, snarare än XML. XML är ett sätt att skapa HTML-liknande språk för att lagra och överföra data.
b) Microsoft Access är egentligen ingen riktig databashanterare, utan ett grafiskt verktyg byggt runt Microsofts riktiga databashanterare, som heter SQL Server.
(Delvis) fel. Microsoft Access är ett grafiskt verktyg byggt runt en "riktig" databashanterar, men även om man kan använda Microsoft Access för att jobba mot en SQL Server-databas, så lagras vanliga Access-databaser med en databashanterare som heter Microsoft Jet.
c) På webben är det vanligt att man låter en webbplats lagra data i en databas. Ofta används MySQL som databashanterare.
Sant.
d) ACID-transaktioner är ett sätt att skydda Internet-banker mot bedrägeriförsök.
Fel. ACID-transaktioner är ett sätt att gruppera flera relaterade operationer (till exempel select- och update-kommandon i SQL) till en logisk enhet, som databashanteraren sen ser till att den bland annat blir atomär, vilket betyder att antingen genomförs samtliga operationer i transaktionen eller också ingen.
e) Databaser används sällan i tekniska tillämpningar som styrsystem och programmering, utan nästan enbart för administrativa ändamål som bokföring, personalregister och liknande.
Fel. Databaser används i alla möjliga tillämpningar, även tekniska, även om det kanske är vanligast med administrativa tillämpningar.
Schema är en beskrivning av strukturen på en databas, medan data är de uppgifter som man lagrat i databasen. Schemat beskriver alltså vilka data som går att lagra i databasen, hur de får se ut, och hur de ska struktureras och hänga ihop.
b)
Grant och revoke är två kommandon som används (normalt av databasadministratören) för att ange vad olika användare får göra med de data som finns i databasen. Med grant delar man ut rättigheter, och med revoke tar man bort dem igen.
c)
Man kan beskriva databasen på en fysisk och en logisk nivå, till exempel med ett fysiskt och ett logiskt schema. Det fysiska schemat beskriver hur databasen lagras, med lagringsstrukturer (kanske ända ner på bit- och byte-nivå), medan det logiska schemat beskriver databasen på en högre nivå, till exempel med vilka tabeller och kolumner som finns.