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 om lösningen ovan:
|
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:
Tabeller (kallas också relationer):
Kandidatnycklar är understrukna. I de tabeller där det finns flera kandidatnycklar, är den första primärnyckel. Referensattribut (kallas också främmande nycklar):
Här nedan visa tabellerna med exempeldata. I tabellerna Organiserar, Anslutna och Bedriver är den enda kandidatnyckeln, och därmed primärnyckeln, sammansatt av båda kolumnerna, men jag vet inte hur man skiver i HTML för att göra ett streck som går genom flera kolumner.
(Observera att var och en av tabellerna Organiserar, Anslutna och Bedriver har en sammansatt kandidatnyckel, och därmed primärnyckel.) Nedan visas create table-kommandon och exempeldata. Det krävs inte som svar, men är med för att underlätta provkörningar. CREATE TABLE Idrotter (Nummer INTEGER NOT NULL PRIMARY KEY, Namn NVARCHAR(20) NOT NULL UNIQUE); INSERT INTO Idrotter VALUES (1, 'fotboll'); INSERT INTO Idrotter VALUES (2, 'snöskolöpning'); INSERT INTO Idrotter VALUES (3, 'schackboxning'); INSERT INTO Idrotter VALUES (4, 'luftballonghockey'); INSERT INTO Idrotter VALUES (5, 'varpa'); INSERT INTO Idrotter VALUES (6, 'hästsko'); INSERT INTO Idrotter VALUES (7, 'strafing'); CREATE TABLE Förbund (Nummer INTEGER NOT NULL PRIMARY KEY, Namn NVARCHAR(40) NOT NULL UNIQUE); INSERT INTO Förbund VALUES (1, 'Svenska Fotbollförbundet'); INSERT INTO Förbund VALUES (2, 'Svenska Skyttesportförbundet'); INSERT INTO Förbund VALUES (3, 'Sveriges schackförbund'); INSERT INTO Förbund VALUES (4, 'Svenska Pistolskytteförbundet'); INSERT INTO Förbund VALUES (5, 'Svenska Ishockeyförbundet'); INSERT INTO Förbund VALUES (6, 'Svenska Varpaförbundet'); INSERT INTO Förbund VALUES (7, 'Sveriges Akademiska Idrottsförbund'); INSERT INTO Förbund VALUES (8, 'Korpen Svenska Motionsidrottsförbundet'); INSERT INTO Förbund VALUES (9, 'Svenska Flygsportförbundet'); INSERT INTO Förbund VALUES (10, 'Nationella Bubbelplastpoppningsförbundet'); CREATE TABLE Organiserar (Förbund INTEGER REFERENCES Förbund (Nummer), Idrott INTEGER REFERENCES Idrotter (Nummer), PRIMARY KEY (Förbund, Idrott)); INSERT INTO Organiserar VALUES (1, 1); INSERT INTO Organiserar VALUES (3, 3); INSERT INTO Organiserar VALUES (6, 5); INSERT INTO Organiserar VALUES (6, 6); INSERT INTO Organiserar VALUES (9, 7); CREATE TABLE Föreningar (Nummer INTEGER NOT NULL PRIMARY KEY, Namn NVARCHAR(30) NOT NULL UNIQUE); INSERT INTO Föreningar VALUES (1, 'Djurgårdens Idrottsförening'); INSERT INTO Föreningar VALUES (2, 'Allmänna Idrottsklubben'); INSERT INTO Föreningar VALUES (3, 'Almby Idrottsklubb'); CREATE TABLE Anslutna (Förening INTEGER REFERENCES Föreningar (Nummer), Förbund INTEGER REFERENCES Förbund (Nummer), PRIMARY KEY (Förening, Förbund)); INSERT INTO Anslutna VALUES (1, 1); INSERT INTO Anslutna VALUES (1, 5); INSERT INTO Anslutna VALUES (2, 1); INSERT INTO Anslutna VALUES (2, 5); INSERT INTO Anslutna VALUES (3, 8); CREATE TABLE Bedriver (Förening INTEGER REFERENCES Föreningar (Nummer), Idrott INTEGER REFERENCES Idrotter (Nummer), PRIMARY KEY (Förening, Idrott)); INSERT INTO Bedriver VALUES (1, 1); INSERT INTO Bedriver VALUES (2, 1); INSERT INTO Bedriver VALUES (3, 3); INSERT INTO Bedriver VALUES (3, 4); INSERT INTO Bedriver VALUES (3, 7); SELECT * FROM Idrotter; SELECT * FROM Förbund; SELECT * FROM Organiserar; SELECT * FROM Föreningar; SELECT * FROM Anslutna; SELECT * FROM Bedriver; |
a) (2p) Vilka olika idrotter organiseras av Svenska Varpaförbundet?
Svar:
Några olika sätt att forumlera sökningen:
SELECT Idrotter.Namn FROM Förbund, Organiserar, Idrotter WHERE Förbund.Nummer = Organiserar.Förbund AND Organiserar.Idrott = Idrotter.Nummer AND Förbund.Namn = 'Svenska Varpaförbundet'; SELECT Idrotter.Namn FROM Förbund JOIN Organiserar ON Förbund.Nummer = Organiserar.Förbund JOIN Idrotter ON Organiserar.Idrott = Idrotter.Nummer WHERE Förbund.Namn = 'Svenska Varpaförbundet'; SELECT Namn FROM Idrotter WHERE Nummer IN (SELECT Idrott FROM Organiserar WHERE Förbund IN (SELECT Nummer FROM Förbund WHERE Namn = 'Svenska Varpaförbundet')); |
b) (2p) De flesta förbunden heter något med Sveriges eller Svenska, till exempel Sveriges Akademiska Idrottsförbund. eller Korpen Svenska Motionsidrottsförbundet. Vilka förbund heter inte något med Sveriges eller Svenska?
Svar:
SELECT Namn FROM Förbund WHERE Namn NOT LIKE '%Sveriges%' AND Namn NOT LIKE '%Svenska%'; |
c) (3p) Vilka idrotter som organiseras av Svenska Flygsportförbundet bedrivs av Almby Idrottsklubb?
Svar:
Ett par olika sätt att forumlera sökningen:
SELECT Idrotter.Namn FROM Föreningar, Bedriver, Idrotter, Organiserar, Förbund WHERE Föreningar.Nummer = Bedriver.Förening AND Bedriver.Idrott = Idrotter.Nummer AND Föreningar.Namn = 'Almby Idrottsklubb' AND Idrotter.Nummer = Organiserar.Idrott AND Organiserar.Förbund = Förbund.Nummer AND Förbund.Namn = 'Svenska Flygsportförbundet'; SELECT Namn FROM Idrotter WHERE Nummer IN (SELECT Idrott FROM Bedriver WHERE Förening IN (SELECT Nummer FROM Föreningar WHERE Namn = 'Almby Idrottsklubb')) AND Nummer IN (SELECT Idrott FROM Organiserar WHERE Förbund IN (SELECT Nummer FROM Förbund WHERE Namn = 'Svenska Flygsportförbundet')); |
d) (3p) Vilken förening bedriver det största antalet idrotter?
Svar:
En lösning med en CTE:
En lösning med en vy:WITH AntalIdrotterPerFörening AS (SELECT Föreningar.Nummer, Föreningar.Namn, COUNT(*) AS Antal FROM Föreningar, Bedriver, Idrotter WHERE Föreningar.Nummer = Bedriver.Förening AND Bedriver.Idrott = Idrotter.Nummer GROUP BY Föreningar.Nummer, Föreningar.Namn) SELECT Nummer, Namn FROM AntalIdrotterPerFörening WHERE Antal = (SELECT MAX(Antal) FROM AntalIdrotterPerFörening); CREATE VIEW AntalIdrotterPerFörening AS SELECT Föreningar.Nummer, Föreningar.Namn, COUNT(*) AS Antal FROM Föreningar, Bedriver, Idrotter WHERE Föreningar.Nummer = Bedriver.Förening AND Bedriver.Idrott = Idrotter.Nummer GROUP BY Föreningar.Nummer, Föreningar.Namn; SELECT Nummer, Namn FROM AntalIdrotterPerFörening WHERE Antal = (SELECT MAX(Antal) FROM AntalIdrotterPerFörening); |
a) Hur kan man få sökningen i deluppgift 3a att gå snabbare?
Svar:
Skapa index på de kolumner som kan komma att användas för att söka fram rader i tabellerna:
Idrotter.Namn är bara med i resultatet från sökningen, och används inte för att söka fram rader, så ett index på den hjälper normalt inte. |
b) Hur kan man få sökningen i deluppgift 3b att gå snabbare?
Svar:
Det är betydligt svårare. Vi vill hitta de namn som inte innehåller orden Sveriges och Svenska, även mitt inne i namnet, och då fungerar det inte med ett vanligt index på Förbund.Namn. Ett vanligt index på ett textfält hjälper oss bara att söka på ett prefix till texten. En del databashanterare har möjlighet till effektiv fritextsökning genom att bygga särskilda index, men annars kan man göra en egen lösning och lagra vilka ord som förekommer i vilka namn, kanske kombinerat med triggers för att uppdatera dem automatiskt. Då behöver man också skriva om frågan, och använda de nya tabeller man skapat. |
c) Hur kan man få sökningen i deluppgift 3c att gå snabbare?
Svar:
Skapa index på de kolumner som kan komma att användas för att söka fram rader i tabellerna:
Idrotter.Namn är bara med i resultatet från sökningen, och används inte för att söka fram rader, så ett index på den hjälper normalt inte. |
Hur skulle man kunna använda en trigger för det? Du behöver inte skriva SQL-kommandon, utan du kan beskriva triggern med ord.
Svar:
Skapa en trigger on delete för tabellen med föreningar,
som gör en insert i tabellen med gamla föreningar.
Så här kan det se ut i Mimer, förutom att Mimer inte har for each row:
CREATE TABLE GamlaFöreningar (Nummer INTEGER NOT NULL PRIMARY KEY, Namn NVARCHAR(30) NOT NULL UNIQUE); @ CREATE TRIGGER GlömOssInte AFTER DELETE ON Föreningar REFERENCING OLD TABLE AS o FOR EACH ROW BEGIN ATOMIC DECLARE GamlaNumret INTEGER; DECLARE GamlaNamnet NVARCHAR(30); SELECT Nummer, Namn INTO GamlaNumret, GamlaNamnet FROM o; INSERT INTO GamlaFöreningar (Nummer, Namn) VALUES (GamlaNumret, GamlaNamnet); END @ |
a) DELETE
Svar:
Tar bort rader ur en tabell. |
b) DROP
Svar:
Tar bort en hel tabell, vy, trigger eller annat objekt i databasens schema. |
c) ROLLBACK
Svar:
Avbryter en transaktion och återställer de ändringar den gjort i databasen. |
d) REVOKE
Svar:
Återkallar en rättighet, till exempel för att lägga till rader i en tabell, som man tidigare delat ut med GRANT. |
Svar:
En eller flera operationer i databasen som hör ihop som en enhet. Om man till exempel vill flytta pengar från ett bankkonto till ett annat måste man både dra bort pengarna från det ena kontot, och lägga till dem till det andra. En transaktion behöver inte nödvändigtvis göra ändringar, så exempelvis en summering av alla bankkontona kan vara en transaktion. |
b) I samband med transaktioner brukar man tala om ACID-egenskaperna. Vilken av bokstäverna A, C, I och D är det som handlar om att förhindra "krockar" mellan samtidiga transaktioner?
Svar:
"I", som i "Isolation", dvs att olika transaktioner ska isoleras från varandra. |
c) Många databashanterare använder lås för att förhindra sådana krockar. Då kan man få deadlock. Vad innebär det?
Svar:
Att en transaktion (låt oss kalla den T1) väntar på att få tillgång till en resurs, typiskt en eller flera rader i en tabell, som en annan transaktion (kallad T2) arbetar med och därför har "låst", så ingen annan transaktion kan komma åt dem. Men samtidigt väntar transaktionen T2 på att få tillgång till en resurs som T1 har låst. De väntar alltså på varandra, och kommer aldrig att kunna fortsätta. (Det kan vara fler än två transaktioner som väntar på varandra, i en cykel.) |
Svar:
Att samma databas kan beskrivas med tre olika scheman, dvs beskrivningar av databasens struktur och vad som går att lagra i den:
|
Svar:
Att man med särskilt formulerade SQL-frågor, gärna med "konstigt" formulerad eller formaterad text som i namn, kan få databashanteraren att göra något annat än vad databasens skapare och programmerare avsett. Till exempel kan det handla om att få tillgång till data som man normalt inte ska ha tillgång till, eller att radera data på ett skadligt sätt. |
b) Är det bra eller dåligt?
Svar:
Dåligt, för det är ett sätt att bryta sig in i databasen. |
c) Visa med ett exempel hur det går till!
Svar:
Antag att man ska skriva in sitt namn och sitt lösenord på en webbsida,
och så visar webbsidan hur mycket pengar man har på sitt konto.
Webbprogrammeraren som skapade webbsidan lägger namnet man skriver in i en variabel som heter InmatatNamn
och lösenordet i en variabel som heter InmatatLösenord.
Därefter används det för uppslagning i tabellen Konton.
SQL-frågan byggs upp som en sträng så här:
string query = "SELECT Belopp FROM Konton WHERE Namn = '" + InmatatNamn + "' AND Lösenord = '" + InmatatLösenord + "'"; Om jag till exempel skriver in namnet Thomas och lösenordet banan, blir SQL-frågan så här: SELECT Belopp FROM Konton WHERE Namn = 'Thomas' AND Lösenord = 'banan' Antag nu att jag vill veta hur mycket pengar kungen har. Jag kan förstås inte kungens lösenord, men om jag skriver in det ganska konstiga namnet Carl XVI Gustaf' OR '1'='2 och vilket lösenord som helst, till exempel banan, kommer SQL-frågan att bli: SELECT Belopp FROM Konton WHERE Namn = 'Carl XVI Gustaf' OR '1'='2' AND Lösenord = 'banan' Villkoret före OR är sant för kungens rad i tabellen. Villkoret efter OR är alltid falskt, och kan ignoreras. Alltså får jag beloppet för kungens konto. |