Ordet "attribut" böjs så här:
ett attribut, två attribut, det attributet, de attributen inte t. ex. en attribut, två attributer |
ER- och EER-diagram kan ritas på flera olika sätt. Om du använder en annan notation än kursboken, måste du förklara den notation som du använder.
Svar:
Kommentarer: Man kan också göra företagen som en egen entitetstyp, och man kan redan i ER-diagramet lägga till ett nummer som surrogatnyckel på problemtyperna.
Du behöver inte skriva create table-kommandon i SQL, men du ska ange vilka relationer som finns och vilka attribut varje relation innehåller. Ange också alla kandidatnycklar, vilken av dessa som är primärnyckel, samt vilka referensattribut som finns och vad de refererar till.
Implementationen ska vara bra.
Svar:
Personer(Nummer, Namn, Telefon, Företag)
Problemtyper(Nummer, Beskrivning)
Rapporter(Nummer, Datum, Tid, Inlämnare)
Gäller(Rapport, Problemtyp)
Primärnycklarna är understrukna. I tabellen Problemtyper är även Beskrivning en kandidatnyckel,
Främmande nycklar:
Rapporter.Inlämnare till Personer.Nummer
Gäller.Rapport till Rapporter.Nummer
Gäller.Problemtyp till Problemtyper.Nummer
Så här kan man också rita upp schemat:
Tabellerna med exempeldata:
Personer | |||
---|---|---|---|
Nummer | Namn | Telefon | Företag |
1 | Anna | 1234 | Polisen |
2 | Bodil | 1234 | null |
3 | Bodil | 019-5678 | Närkefrakt |
Problemtyper | |
---|---|
Nummer | Beskrivning |
1 | stod i vägen |
2 | slängd i en snödriva |
3 | rysk invasion |
Rapporter | |||
---|---|---|---|
Nummer | Datum | Tid | Inlämnare |
1 | 2022-12-24 | 10:22:00 | 2 |
2 | 2023-01-10 | 13:11:00 | 2 |
3 | 2023-01-11 | 04:22:00 | 3 |
Gäller | |
---|---|
Rapport | Problemtyp |
1 | 1 |
2 | 1 |
2 | 2 |
3 | 1 |
3 | 2 |
Nedan visas create table-kommandon och exempeldata, för att underlätta provkörningar.
DROP TABLE Personer CASCADE; DROP TABLE Problemtyper CASCADE; DROP TABLE Rapporter CASCADE; DROP TABLE Gäller CASCADE; CREATE TABLE Personer (Nummer INTEGER NOT NULL PRIMARY KEY, Namn NVARCHAR(10) NOT NULL, Telefon NVARCHAR(10) NOT NULL, Företag NVARCHAR(10) NULL); INSERT INTO Personer VALUES (1, 'Anna', '1234', 'Polisen'); INSERT INTO Personer VALUES (2, 'Bodil', '1234', NULL); INSERT INTO Personer VALUES (3, 'Bodil', '019-5678', 'Närkefrakt'); CREATE TABLE Problemtyper (Nummer INTEGER NOT NULL PRIMARY KEY, Beskrivning NVARCHAR(21) NOT NULL UNIQUE); INSERT INTO Problemtyper VALUES (1, 'stod i vägen'); INSERT INTO Problemtyper VALUES (2, 'slängd i en snödriva'); INSERT INTO Problemtyper VALUES (3, 'rysk invasion'); CREATE TABLE Rapporter (Nummer INTEGER NOT NULL PRIMARY KEY, Datum DATE NOT NULL, Tid TIME NOT NULL, Inlämnare INTEGER NOT NULL REFERENCES Personer(Nummer)); INSERT INTO Rapporter VALUES (1, DATE '2022-12-24', TIME '10:22:00', 2); INSERT INTO Rapporter VALUES (2, DATE '2023-01-10', TIME '13:11:00', 2); INSERT INTO Rapporter VALUES (3, DATE '2023-01-11', TIME '04:22:00', 3); CREATE TABLE Gäller (Rapport INTEGER NOT NULL REFERENCES Rapporter(Nummer), Problemtyp INTEGER NOT NULL REFERENCES Problemtyper(Nummer), PRIMARY KEY (Rapport, Problemtyp)); INSERT INTO Gäller VALUES (1, 1); INSERT INTO Gäller VALUES (2, 1); INSERT INTO Gäller VALUES (2, 2); INSERT INTO Gäller VALUES (3, 1); INSERT INTO Gäller VALUES (3, 2); SELECT * FROM Personer; SELECT * FROM Problemtyper; SELECT * FROM Rapporter; SELECT * FROM Gäller;
Svar:
Svar:
CHECK-villkor används för att kontrollera data på en rad. Till exempel kanske man vill att beskrivningen av problemtyperna alltid ska bestå av minst två ord, och då skulle man kunna ange att den måste innehålla ett blanktecken:
CREATE TABLE Problemtyper (Nummer INTEGER NOT NULL PRIMARY KEY, Beskrivning NVARCHAR(21) NOT NULL UNIQUE CHECK (Beskrivning LIKE '% %'));
FOREIGN KEY används för att ange främmande nycklar. Man kan ange en främmande nyckel med bara REFERENCES, eller som en egen del när man skapar tabellen, exempelvis:
Databashanteraren kommer att upprätthålla referensintegriteten för de främmande nycklar som man angivit. Den använder dem inte för att automatiskt koppla ihop tabeller i SQL-frågor med flera tabeller.CREATE TABLE Rapporter (Nummer INTEGER NOT NULL PRIMARY KEY, Datum DATE NOT NULL, Tid TIME NOT NULL, Inlämnare INTEGER NOT NULL, FOREIGN KEY (Inlämnare) REFERENCES Personer(Nummer));
NOT NULL används för att ange att en ruta i tabellen inte får lämnas tom, som de tre första kolumnerna i tabellen Personer, men inte den sista:
CREATE TABLE Personer (Nummer INTEGER NOT NULL PRIMARY KEY, Namn NVARCHAR(10) NOT NULL, Telefon NVARCHAR(10) NOT NULL, Företag NVARCHAR(10) NULL);
PRIMARY KEY används för att ange primärnycklar, som kolumnen Nummer i tabellen ovan.
UNIQUE används för att ange alternativnycklar, förutom primärnyckeln, som i tabellen Problemtyper ovan, där Nummer är primärnyckel och Beskrivning är en alternativnyckel.
a) (2p) Jag har telefonnummer 070-7347013. Vilka datum har jag skickat in rapporter om problem?
Svar:
SELECT DISTINCT Datum FROM Rapporter, Personer WHERE Rapporter.Inlämnare = Personer.Nummer AND Personer.Telefon = '070-7347013';Ett alternativ med en explicit join:
SELECT DISTINCT Datum FROM Rapporter JOIN Personer ON Rapporter.Inlämnare = Personer.Nummer WHERE Personer.Telefon = '070-7347013';Ett alternativ med nästlade frågor:
SELECT DISTINCT Datum FROM Rapporter WHERE Inlämnare IN (SELECT Nummer FROM Personer WHERE Telefon = '070-7347013');
b) (2p) Telefonnummer i Örebro börjar på 019- och telefonnummer i Fjugesta börjar på 0585-. Sammanlagt hur många personer har telefonnummer i Örebro och Fjugesta?
Svar:
SELECT COUNT(*) FROM Personer WHERE Telefon LIKE '019-%' OR Telefon LIKE '0585-%';
c) (2p) Vilka typer av problem rapporterades igår (2023-01-10)? Vi vill veta beskrivningarna, inte bara numren.
Svar:
SELECT DISTINCT Problemtyper.Beskrivning FROM Rapporter, Gäller, Problemtyper WHERE Rapporter.Nummer = Gäller.Rapport AND Gäller.Problemtyp = Problemtyper.Nummer AND Rapporter.Datum = DATE '2023-01-10';Ett alternativ med en explicit join:
SELECT DISTINCT Problemtyper.Beskrivning FROM Rapporter JOIN Gäller ON Rapporter.Nummer = Gäller.Rapport JOIN Problemtyper ON Gäller.Problemtyp = Problemtyper.Nummer WHERE Rapporter.Datum = DATE '2023-01-10';Ett alternativ med nästlade frågor:
SELECT Beskrivning FROM Problemtyper WHERE Nummer IN (SELECT Problemtyp FROM Gäller WHERE Rapport IN (SELECT Nummer FROM Rapporter WHERE Datum = DATE '2023-01-10'));
d) (3p) Vilket problem är vanligast? Vi vill alltså veta beskrivningen på den problemtyp som det finns flest rapporter om.
Svar:
CREATE VIEW AntalRapporter AS SELECT Problemtyp AS Typ, COUNT(*) AS Antal FROM Gäller GROUP BY Problemtyp; SELECT Beskrivning FROM Problemtyper WHERE Nummer IN (SELECT Typ FROM AntalRapporter WHERE Antal IN (SELECT MAX(Antal) FROM AntalRapporter));Ett alternativ med en CTE:
WITH AntalRapporter AS (SELECT Problemtyp AS Typ, COUNT(*) AS Antal FROM Gäller GROUP BY Problemtyp) SELECT Beskrivning FROM Problemtyper WHERE Nummer IN (SELECT Typ FROM AntalRapporter WHERE Antal IN (SELECT MAX(Antal) FROM AntalRapporter));
e) (2p) Vilka problemtyper finns det ingen rapport alls om?
Svar:
SELECT Beskrivning FROM Problemtyper WHERE Nummer NOT IN (SELECT Problemtyp FROM Gäller);
a) Det visar sig att det inte finns några index alls i databasen. Vilka index bör vi skapa för att sökningen ska gå snabbare?
Svar:
Gäller.Rapport
Gäller.Problemtyp
Problemtyper.Nummer
Rapporter.Nummer
Rapporter.Datum
b) Ge exempel på något index som inte skulle få sökningen att gå snabbare, och förklara varför det indexet inte skulle hjälpa.
Svar:
Problemtyper.Beskrivning - bara med i resultatet, används inte för sökningar
Rapporter.Tid - inte alls med i frågan
c) I a-uppgiften ovan stod det att det inte fanns några index alls i databasen. Nästan alla databashanterare, till exempel Mimer och MySQL, skapar en del index automatiskt. Vilka, och varför?
Svar:
De skapar index på angivna primär- och alternativnycklar, dvs som deklarerats med PRIMARY KEY eller med UNIQUE. Det är dels för att i synnerhet primärnyckeln ofta används i sökningar, så man vill antagligen ha index på dem, och dessutom är de unika, dvs har god selektivitet. Det kanske allra viktigaste skälet är att databashanteraren måste upprätthålla nycklarnas unikhet, så varje gång man sätter in en rad, eller ändrar värdet på en nyckel på en rad, måste man annars läsa igenom hela tabellen för att se om det finns dubbletter. Databashanteraren måste också upprätthålla referensintegritet, och främmande nycklar refererar alltid till en primär- eller alternativnyckel, och för att kontrollera referensintegriteten behöver man slå upp värdet på nyckeln i den tabell som den främmande nyckeln refererar till.
Svar:
Efter COMMIT sparas ändringarna permanent i databasen. Internt kan det ske genom att databashanteraren redan gjort ändringarna direkt i databasen, och helt enkelt låter bli att ändra tillbaka. Det kan också ske genom att de nya versionerna av data lagrats på en separat plats, och nu integreras med den vanliga databasen. Om det skulle uppstå ett fel under commit-processen så att committen inte kan genomföras, till exempel vid vissa typer av samtidighetshantering där konflikter kan upptäckas då, görs i stället en rollback.
Efter ROLLBACK tas alla ändringar som transaktionen gjort bort ur databasen. (Internt kan det ske genom att databashanteraren, som redan gjort ändringarna direkt i databasen, ändrar tillbaka allt som ändras. Det kan också ske genom att de nya versionerna av data, som lagrats på en separat plats, helt enkelt kastas bort i stället för att integreras med den vanliga databasen.)
Om transaktionen avbrutits av ett fel, tas alla ändringar som transaktionen gjort bort ur databasen, på samma sätt som vid ROLLBACK. (Om transaktionen avbröts av ett strömavbrott, eller att databashanteraren plötsligt stängdes av på något annat sätt, kan det ske som en del av återstartsprocessen, även kallad "recovery". Om ändringarna har gjorts direkt i databasen, måste databashanteraren läsa loggfilen för att veta vilka ändringar som gjorts, så de går att ändra tillbaka.)