En liten saga om en databas 🎂

Kapitel 1 – En födelsedag i solsken

Solen strålade in genom gardinerna i det lilla huset där Maria bodde. Det var hennes födelsedag, och världen utanför verkade veta om det. Fåglarna kvittrade ovanligt högt, som om de försökte sjunga ”Ja, må hon leva”. Doften av nybryggt kaffe spred sig från köket och blandades med den söta doften av syrener från trädgården.

Maria sträckte på sig i sängen och log. Hon visste att Pelle och Kalle, hennes bästa vänner, hade planerat något. De hade viskat i flera dagar, skrattat i smyg och sett sådär hemlighetsfulla ut som bara vänner kan när de är ute på äventyr.

Men Pelle och Kalle hade ett problem. Deras fickor var nästan lika tomma som Marias kakburk efter jul. Om de ville köpa en fin present måste de vara kreativa.

Och här, kära läsare, behöver vi hjälp av en databas. För att hålla reda på alla i sagan – vilka de är, vad de gör och vad som händer – skapar vi vår första tabell.


Kapitel 2 – Personerna i sagan

För att en dator ska förstå vilka som är med, börjar vi med att skapa en lista över våra huvudpersoner.

I människovärlden räcker det att peka och säga “där är Maria”. Men databaser behöver mer ordning än så. Därför får alla en liten nummerlapp – en id. Den fungerar som en hemlig namnbricka bakom kulisserna och gör att vi kan peka ut rätt Maria även om vi träffar fler som heter likadant.

För att vår databas ska kunna hålla koll på våra hjältar ger vi dem var sitt id. Detta gör man ofta i databastabeller för att kunna skilja på saker och ting. Varje tabell har en id-kolumn som gör att vi kan identifiera en specifik rad, oavsett vilken ordning vi har i tabellen. Vi brukar kalla dessa för Primär Nyckel (Primary Key). Den är kung i sin egen tabell och ser till att varje rad är unik och lätt att hitta.

CREATE TABLE Personer (
  id INTEGER PRIMARY KEY,
  namn TEXT NOT NULL
);

INSERT INTO Personer (id, namn) VALUES
(1, 'Maria'),
(2, 'Pelle'),
(3, 'Kalle');

Vår Personer-tabell ser nu ut som en prydlig gästlista:

id (Primary Key)namn
1Maria
2Pelle
3Kalle

Kapitel 3 – Saker som spelar roll

Utanför huset låg en liten hög med pantburkar som Pelle och Kalle hade samlat ihop. Pelle hade sparat burkarna länge, för att dryga ut veckopengen. Han brukade tänka att varje burk var ett steg närmare nästa Fantomen-tidning som han alltid köpte i kiosken på hörnet. Men idag var det viktigare saker än serietidningar – idag fyllde Maria år, och det måste firas.

Kalle däremot hade en annan syn på burkarna. Han tyckte det var kul att ställa upp dem på en sten och skjuta på dem med sin gamla slangbella. Pang! Klirr! skrattade han varje gång burken flög iväg. Pelle rynkade pannan varje gång. ”Sluta nu, du förstör ju streckkoderna. Jag kan inte panta dem om du gör hål rakt igenom!” Kalle ryckte på axlarna. ”Men det är kul ju.”

Det var alltid så med de två. Pelle räknade, Kalle lekte. Men den här gången hade de samma mål: Maria skulle ha en present.

Inne i stan fanns butiken. Den hade stora glasrutor och var fylld med allt sådant som, i Pelles och Kalles ögon, ”tjejer tycker om”. Absolut inga leksaksvapen eller actionfigurer som de själva brukade drömma om. Här fanns i stället kläder med spets, skor som blänkte i ljuset, och hyllor fulla av små praktiska saker som vuxna kvinnor säkert använde.

Men längst fram i skyltfönstret, som för att vänta just på dem, stod den. En söt docka, med lockigt hår och en klänning som påminde lite om Marias favoritklänning. Den såg nästan ut som om den tillhörde henne redan.

”Det där blir perfekt”, sa Pelle. ”Dockor?” muttrade Kalle, men nickade. Han visste att Maria skulle bli glad.

Och vad är väl en födelsedag utan tårta? De vuxna kanske hade glömt (det trodde de, för vuxna hade ofta viktigare saker för sig), så Pelle och Kalle viskade att de nog borde köpa en liten tårta också. Bara för säkerhets skull.

För att spara sakerna i vår databas:

Precis som personerna får även sakerna sina egna id. Det gör att vi kan tala om för databasen exakt vilken sak som dyker upp i historien: pantburken, dockan eller tårtan. Fältet pris sparas som heltal så att vår berättelse kan räkna på kronorna utan att oroa sig för komplicerad decimalmatematik. Och där värdet saknas – som för själva “pengar”-påsen – låter vi NULL tala om att priset inte är definierat ännu. NULL betyder inte noll, utan snarare “okänt” eller “inte tillämpligt”. Det är som en tom plats i sagan som väntar på att fyllas i.

CREATE TABLE Saker (
  id INTEGER PRIMARY KEY,
  namn TEXT NOT NULL,
  pris INTEGER
);

INSERT INTO Saker (id, namn, pris) VALUES
(1, 'pengar', NULL),
(2, 'pantburk', 1),
(3, 'docka', 70),
(4, 'tårta', 30);
id (Primary Key)namnpris
1pengarnull
2pantburk1
3docka70
4tårta30

Kapitel 4 – Händelser som driver allt framåt

En saga är aldrig stilla. Någon fyller år, någon får pengar, någon köper något, någon pantar burkar. För att hålla reda på detta gör vi en lista över händelserna – själva verben i berättelsen.

Notering: Vi skriver tabellnamnet som Handelser utan “ä” för att göra det enkelt i SQL, även om det egentligen stavas “händelser” på svenska. Många databaser och verktyg fungerar bättre med enbart A-Z.

CREATE TABLE Handelser (
  id INTEGER PRIMARY KEY,
  handelse TEXT NOT NULL
);

INSERT INTO Handelser (id, handelse) VALUES
(1, 'få'),
(2, 'ha'),
(3, 'panta'),
(4, 'köpa'),
(5, 'ge'),
(6, 'äta'),
(7, 'fylla år');
id (Primary Key)handelse
1
2ha
3panta
4köpa
5ge
6äta
7fylla år

Mellanspel – När sagan ska sys ihop

Nu har vi huvudpersoner, saker och händelser, var och en i sin prydliga tabell. Men hur vet databasen att det var just Pelle som pantade burkar, och vilka burkar det gällde? Här kliver vår länk-tabell in på scenen. Tänk den som sagans regissör som håller reda på vem som gjorde vad, med vilken sak och för vems skull.

Genom att ge varje koppling ett eget id kan vi följa ordningen på händelserna. Kolumnerna person1_id, sak_id och person2_id pekar tillbaka till tabellerna vi redan byggt. När en id-kolumn i en tabell pekar på en primärnyckel i en annan tabell, kallar vi den för en Främmande Nyckel (Foreign Key). Så, en primärnyckel är kung i sitt eget slott, men en främmande nyckel är en ambassadör som besöker ett annat slott för att skapa en koppling.

CREATE TABLE Koppling (
  id INTEGER PRIMARY KEY,
  person1_id INTEGER NOT NULL,
  handelse_id INTEGER NOT NULL,
  sak_id INTEGER,
  person2_id INTEGER,
  FOREIGN KEY (person1_id) REFERENCES Personer(id),
  FOREIGN KEY (handelse_id) REFERENCES Handelser(id),
  FOREIGN KEY (sak_id) REFERENCES Saker(id),
  FOREIGN KEY (person2_id) REFERENCES Personer(id)
);

Varje FOREIGN KEY är ett löfte: värdet som står här måste finnas som en PRIMARY KEY i den andra tabellen. Detta kallas referensintegritet och fungerar som sagans magiska lag. Den hindrar oss från att råka skriva att “person nummer 99” köpte en tårta, om det inte finns någon person med id 99 i vår Personer-tabell. På så sätt håller vi berättelsen sann och konsekvent.

Om vi exempelvis vill spara att Pelle pantade en burk, skulle vi lägga in det så här:

INSERT INTO Koppling (id, person1_id, handelse_id, sak_id, person2_id)
VALUES (1, 2, 3, 2, NULL);
id (Primary Key)person1_id (Foreign Key)handelse_id (Foreign Key)sak_id (Foreign Key)person2_id (Foreign Key)
12 (Pelle)3 (panta)2 (pantburk)null

Här ser vi att person1_id (2) pekar på Pelle i Personer, handelse_id (3) pekar på “panta” i Handelser, och sak_id (2) pekar på “pantburk” i Saker. Eftersom ingen annan är direkt inblandad i denna händelse, lämnar vi person2_id tomt (NULL).


Kapitel 5 – Pengar i fickorna

Pelle räknade sina skrynkliga sedlar: 25 kronor. Kalle vände upp och ner på fickan, några mynt föll klirrande ner på bordet: 50 kronor. Maria hade ingenting ännu, men det visste hon inte – hennes moster var redan på väg med ett kuvert som innehöll 100 kronor.

Sådant här måste man spara ordentligt i en databas.

CREATE TABLE Ekonomi (
  id INTEGER PRIMARY KEY,
  person_id INTEGER NOT NULL,
  saldo INTEGER NOT NULL,
  FOREIGN KEY (person_id) REFERENCES Personer(id)
);

INSERT INTO Ekonomi (id, person_id, saldo) VALUES
(1, 1, 0),   -- Maria börjar utan pengar
(2, 2, 25),  -- Pelle har 25:-
(3, 3, 50);  -- Kalle har 50:-
id (Primary Key)person_id (Foreign Key)saldo
11 (Maria)0
22 (Pelle)25
33 (Kalle)50

Här ser vi varför FOREIGN KEY är så kära för databasen: varje rad i Ekonomi måste peka på en verklig person i Personer. Det är som att kassaboken alltid frågar “vems pengar är det här egentligen?” och nöjer sig först när svaret finns i personlistan. Utan den regeln skulle vi kunna ha pengar som tillhörde ett spöke, en summa pengar utan ägare, vilket skulle skapa oreda i vår saga.


Kapitel 6 – Kuvertet från mostern

På förmiddagen knackade det på dörren hemma hos Maria. Utanför stod hennes moster, med ett varmt leende och ett litet kuvert i handen. ”Grattis på födelsedagen, hjärtat”, sa hon och räckte fram det. Maria spratt till av glädje. Inuti kuvertet låg en hundralapp – hennes alldeles egna pengar.

I databasen skriver vi in det så här, med kommandot UPDATE som ändrar ett värde som redan finns:

UPDATE Ekonomi
SET saldo = saldo + 100
WHERE person_id = 1;

Före:

person_idsaldo
1 (Maria)0

Efter:

person_idsaldo
1 (Maria)100

Kapitel 7 – Burkar, skrammel och stora ögon

Dagen efter bestämde sig Pelle och Kalle för att gå till återvinningen. På ryggen hade de varsin kasse full av burkar. Solen lyste på aluminiumburkarna så de glittrade som silvermynt i en sagoskatt.

”Tänk vad fint”, sa Pelle och höll hårt i sin kasse. Han såg framför sig summan ticka upp på pantmaskinens skärm. Kalle däremot… han såg något helt annat. Rader av burkar, människor som kom och gick, berg av aluminiumburkar i säckar vid sidan om. Han kände hur det kliade i fingrarna. Tänk om han bara kunde ta fram slangbellan och pang! — ljudet, känslan, skratten.

”Kalle!” väste Pelle. ”Tänk på streckkoderna! Vi behöver varenda krona.” Kalle suckade och nickade. Han visste att Pelle hade rätt. Även om det var frestande att fantisera om burkar som flyger i luften, så var dockan i skyltfönstret ännu viktigare.

För att spara händelsen i databasen:

-- Pelle pantar burkar
INSERT INTO Koppling (id, person1_id, handelse_id, sak_id, person2_id)
VALUES (1, 2, 3, 2, NULL);

-- Kalle pantar burkar
INSERT INTO Koppling (id, person1_id, handelse_id, sak_id, person2_id)
VALUES (2, 3, 3, 2, NULL);
id (Primary Key)person1_id (Foreign Key)handelse_id (Foreign Key)sak_id (Foreign Key)person2_id (Foreign Key)
12 (Pelle)3 (panta)2 (pantburk)null
23 (Kalle)3 (panta)2 (pantburk)null

Nu ser vi vår länk-tabell arbeta. person1_id pekar på vem som utförde händelsen (Pelle med id 2), handelse_id berättar vilket verb som gäller (panta med id 3), och sak_id beskriver rekvisitan (pantburk med id 2). person2_id får vila (NULL) när ingen annan är direkt inblandad. Det är precis därför vi matar in sagan på det här sättet: vi kan sätta ihop hela berättelsen igen genom att följa ID-spåren som små brödsmulor.


Kapitel 8 – Skrammel blir till mynt

Glada med pengarna de fått ihop och alldeles upplyfta av det mysiga ljudet av burkarna som krossades, vandrade Pelle och Kalle iväg till kassan. Pantkvittot knastrade lite i Pelles hand, som en magisk biljett.

Kassörskan log och bytte kvittot mot skramlande mynt. Det var inte mycket, men i deras ögon lyste de som guld. Pelle räknade noga, medan Kalle mest skakade fickan för att höra ljudet.

”Nu har vi råd”, sa Pelle stolt. ”Råd till vad då?” frågade Kalle och låtsades som om han glömt. ”Till dockan. Och kanske… om vi har tur, till en liten tårta också.”

I databasen uppdaterar vi deras saldo:

-- Pelle får pantpengar (vi antar att de fick 5 kr var)
UPDATE Ekonomi
SET saldo = saldo + 5
WHERE person_id = 2;

-- Kalle får pantpengar
UPDATE Ekonomi
SET saldo = saldo + 5
WHERE person_id = 3;

Före:

person_idsaldo
2 (Pelle)25
3 (Kalle)50

Uppdatering:

person_idsaldo
2 (Pelle)+ 5
3 (Kalle)+ 5

Efter:

person_idsaldo
2 (Pelle)30
3 (Kalle)55

Kapitel 9 – Dockan i skyltfönstret

När de kom fram till stan var luften fylld av doften från bageriet på hörnet och ljudet av spårvagnen som gnisslade förbi. Pelle pekade genast mot det stora skyltfönstret. Där stod den – dockan.

Hon stod på en liten piedestal, med lockigt hår och en klänning som såg ut att vara sydd just för Maria. Det var som om dockan log åt dem, redan redo att följa med hem.

”Det är den vi ska ha,” sa Pelle med säker röst. Kalle nickade. ”Hon kommer bli glad. Men hoppas vi har tillräckligt.”

De gick in i butiken. Expediten slog in dockan i prasslande papper, knöt ett litet sidenband runt, och lade försiktigt ner den i en påse. Pelle och Kalle kände sig plötsligt stora, nästan vuxna. De höll hårt i påsen när de gick mot kassan.

-- Pelle köper (halva) dockan till Maria
INSERT INTO Koppling (id, person1_id, handelse_id, sak_id, person2_id)
VALUES (3, 2, 4, 3, 1);

-- Kalle köper (halva) dockan till Maria
INSERT INTO Koppling (id, person1_id, handelse_id, sak_id, person2_id)
VALUES (4, 3, 4, 3, 1);
id (Primary Key)person1_id (Foreign Key)handelse_id (Foreign Key)sak_id (Foreign Key)person2_id (Foreign Key)
32 (Pelle)4 (köpa)3 (docka)1 (Maria)
43 (Kalle)4 (köpa)3 (docka)1 (Maria)

Innan köp:

person_idsaldo
2 (Pelle)30
3 (Kalle)55

Ekonomin uppdateras:

Eftersom Pelle bara hade 30 kronor bestämde sig Kalle för att låna ut en femma innan de betalade i kassan.

-- Kalle lånar ut 5 kr till Pelle så att båda når upp till sin del av kostnaden
UPDATE Ekonomi
SET saldo = saldo - 5
WHERE person_id = 3;

UPDATE Ekonomi
SET saldo = saldo + 5
WHERE person_id = 2;

-- Dra av kostnaden från deras ekonomi (de delar på 70 kr)
UPDATE Ekonomi
SET saldo = saldo - 35
WHERE person_id = 2;

UPDATE Ekonomi
SET saldo = saldo - 35
WHERE person_id = 3;
person_idsaldo
2 (Pelle)0
3 (Kalle)15

Nu gick båda ut ur butiken utan att hamna på minus – Pelle nollställde sin plånbok och Kalle hade fortfarande en liten buffert kvar.

Lägg märke till hur samma sak_id (3, för dockan) används två gånger. Eftersom vi sparade dockan med sitt id räcker det att referera till numret för att båda köpen ska handla om samma present. Ekonomi-tabellen använder i sin tur person_id för att dra pengar från rätt plånbok. På det viset går pengarna, händelsen och presenten att följa utan att databasen blandar ihop något.


Kapitel 10 – Bageriet och himmelska dofter

När de gick ut från butiken bar Kalle på påsen som om den vore gjord av glas. Dockan var tryggt inslagen, redo att göra Maria lycklig.

Men något fattades. En födelsedag utan tårta var som en bok utan slut. Så de fortsatte längs kullerstensgatan tills de nådde bageriet på hörnet.

Dörren slog upp och en våg av dofter vällde ut. Nybakat bröd, kanelbullar, wienerbröd och gräddtårtor i långa rader. Det var nästan för mycket. Kalle sniffade och sa: ”Det här måste vara himmelriket som prällen brukar prata om på julmässan och påsk.” Pelle fnös. ”Ja, fast kyrkan är tråkigare. Här får man åtminstone äta upp himmelriket.”

Bakom disken stod en kvinna med mjöl på förklädet. Hon log åt dem, som om hon förstod precis varför de kommit. ”En tårta, tack,” sa Pelle. ”Till Maria. Hon fyller år.” Expediten packade varsamt ner en liten tårta, med grädde som såg ut som snödrivor och jordgubbar som glänste som rubiner.

På väg mot kassan bar de in en stack lådor åt bagaren och fick 15 kronor var som tack. Med lite extra klirr i fickorna kunde de köpa tårtan utan att riskera röda siffror.

-- Bonus för att bära mjölsäckar åt bagaren
UPDATE Ekonomi
SET saldo = saldo + 15
WHERE person_id = 2;

UPDATE Ekonomi
SET saldo = saldo + 15
WHERE person_id = 3;

-- Dra av kostnaden för tårtan (de delar på 30 kr)
UPDATE Ekonomi
SET saldo = saldo - 15
WHERE person_id = 2;

UPDATE Ekonomi
SET saldo = saldo - 15
WHERE person_id = 3;

Nu sparar vi också händelsen i vår Koppling-tabell:

-- Pelle köper (halva) tårtan
INSERT INTO Koppling (id, person1_id, handelse_id, sak_id, person2_id)
VALUES (5, 2, 4, 4, NULL);

-- Kalle köper (halva) tårtan
INSERT INTO Koppling (id, person1_id, handelse_id, sak_id, person2_id)
VALUES (6, 3, 4, 4, NULL);

-- Pelle ger tårtan (för festen)
INSERT INTO Koppling (id, person1_id, handelse_id, sak_id, person2_id)
VALUES (7, 2, 5, 4, 1);
id (Primary Key)person1_id (Foreign Key)handelse_id (Foreign Key)sak_id (Foreign Key)person2_id (Foreign Key)
52 (Pelle)4 (köpa)4 (tårta)null
63 (Kalle)4 (köpa)4 (tårta)null
72 (Pelle)5 (ge)4 (tårta)1 (Maria)

Efter besöket hos bagaren

person_idsaldo
2 (Pelle)0
3 (Kalle)15

Kapitel 11 – Presenten och den första tårtan

Solen hade börjat luta sig ner mot eftermiddagen när Pelle och Kalle äntligen stod utanför Marias hus. Påsen med dockan knastrade i Kalles hand, och den lilla tårtan balanserades försiktigt av Pelle.

De knackade på, och Maria öppnade dörren med ett stort leende. ”Grattis på födelsedagen!” ropade de i kör, nästan för högt.

Kalle räckte fram påsen, Pelle ställde tårtan på bordet. ”Vi… vi ville fira dig,” mumlade Pelle, plötsligt lite blyg. Maria slog händerna för munnen. ”Åh, ni är bäst!”

De skrattade, fnissade och satte sig tillsammans vid köksbordet. Snart var tallrikarna framme, och tårtan skars upp i prydliga, lite ojämna bitar. Grädden kletade sig fast vid näsor och mungipor, och jordgubbarna försvann först av allt.

-- Pelle ger dockan till Maria
INSERT INTO Koppling (id, person1_id, handelse_id, sak_id, person2_id)
VALUES (8, 2, 5, 3, 1);

-- Kalle ger dockan till Maria
INSERT INTO Koppling (id, person1_id, handelse_id, sak_id, person2_id)
VALUES (9, 3, 5, 3, 1);

-- Alla tre äter av den första tårtan
INSERT INTO Koppling (id, person1_id, handelse_id, sak_id, person2_id)
VALUES (10, 1, 6, 4, NULL),
       (11, 2, 6, 4, NULL),
       (12, 3, 6, 4, NULL);
id (Primary Key)person1_id (Foreign Key)handelse_id (Foreign Key)sak_id (Foreign Key)person2_id (Foreign Key)
82 (Pelle)5 (ge)3 (docka)1 (Maria)
93 (Kalle)5 (ge)3 (docka)1 (Maria)
101 (Maria)6 (äta)4 (tårta)null
112 (Pelle)6 (äta)4 (tårta)null
123 (Kalle)6 (äta)4 (tårta)null

Nu märks en annan finess med vårt sätt att mata in sagan: vi kan skilja på vem som ger (person1_id) och vem som får (person2_id). Samma sak_id på dockan visar att det fortfarande är exakt den gåvan som rör sig mellan vännerna. När Maria äter tårta lämnar person2_id platsen tom, och databasen förstår att det inte finns någon mottagare – bara en mycket nöjd födelsedagsfirare.


Kapitel 12 – Den stora överraskningen

Just som de var färdiga med sista biten, hördes röster och skratt utifrån. Dörren öppnades och in vällde Marias föräldrar, syskon, mostrar och en och annan granne.

Och med sig hade de… ännu en tårta. En stor, pampig sak, fylld med hallon och choklad.

”Överraskning!” ropade alla.

Maria skrattade så hon fick hålla sig för magen. ”Men jag är ju redan proppmätt!” ”Det gör inget,” log hennes mamma. ”Det finns alltid plats för mer tårta på sin födelsedag.”

Så de åt igen. Pelle och Kalle såg på varandra och fnissade. Två tårtor på samma dag. Om det fanns ett himmelrike, då måste det vara just detta.

-- Alla tre äter av familjens tårta också
INSERT INTO Koppling (id, person1_id, handelse_id, sak_id, person2_id)
VALUES (13, 1, 6, 4, NULL),
       (14, 2, 6, 4, NULL),
       (15, 3, 6, 4, NULL);
id (Primary Key)person1_id (Foreign Key)handelse_id (Foreign Key)sak_id (Foreign Key)person2_id (Foreign Key)
131 (Maria)6 (äta)4 (tårta)null
142 (Pelle)6 (äta)4 (tårta)null
153 (Kalle)6 (äta)4 (tårta)null

Och så slutade dagen med skratt, två sorters tårta och en docka i nytt hem. Maria kände sig älskad, Pelle och Kalle kände sig stora och viktiga. Och i databasen stod allt sparat, redo för nästa äventyr de tre vännerna skulle ge sig ut på tillsammans.

Epilog – Regler, index och hur sagan kan läsas

När man bygger databaser i verkligheten sätter man regler som ser till att det inte blir kaos. Dessa kallas constraints (begränsningar). De är som kungliga påbud i sagans värld.

UNIQUE är ett påbud som säger: “Inga två personer i denna saga får ha exakt samma namn!” Detta förhindrar förvirring om det skulle dyka upp en till Kalle. CHECK är ett annat påbud: “Ingen persons saldo får någonsin understiga noll!” Databasen blir då en trogen väktare som ser till att ingen spenderar pengar de inte har.

Notering för SQLite: I SQLite kan man inte lägga till CHECK-begränsningar med ALTER TABLE. Därför måste CHECK definieras direkt när tabellen skapas. För andra databaser som MySQL eller PostgreSQL fungerar ALTER TABLE.

-- Så här skulle vi skapa Personer med UNIQUE:
CREATE TABLE Personer (
  id INTEGER PRIMARY KEY,
  namn TEXT NOT NULL UNIQUE
);

-- Så här skulle vi skapa Ekonomi med CHECK (i SQLite måste det göras vid CREATE):
CREATE TABLE Ekonomi (
  id INTEGER PRIMARY KEY,
  person_id INTEGER NOT NULL,
  saldo INTEGER NOT NULL CHECK (saldo >= 0),
  FOREIGN KEY (person_id) REFERENCES Personer(id)
);
id (Primary Key)namn
1Maria
2Pelle
3Kalle
id (Primary Key)person_id (Foreign Key)saldo
11 (Maria)0
22 (Pelle)0
33 (Kalle)0

För att databasen ska vara snabb när man letar efter något kan man skapa ett index. Ett index är som ett register i slutet av en bok – det hjälper databasen att blixtsnabbt hitta rätt person eller sak utan att behöva läsa igenom hela sagan från början till slut varje gång.

CREATE INDEX idx_personer_namn ON Personer(namn);
CREATE INDEX idx_handelse_namn ON Handelser(handelse);

Att läsa sagan tillbaka ur databasen

Vi har matat in hela berättelsen i vår databas. Men vad gör man om man vill höra sagan igen? Då använder vi JOINs – de magiska broarna som binder ihop tabellerna med hjälp av våra primära och främmande nycklar. Varje gång vi ber databasen att läsa upp sagan följer den spåren vi skapat.

Alla händelser i sagan

SELECT
  p1.namn AS Person,
  h.handelse AS Gör,
  s.namn AS Sak,
  p2.namn AS Mottagare
FROM Koppling k
LEFT JOIN Personer p1 ON k.person1_id = p1.id
LEFT JOIN Handelser h ON k.handelse_id = h.id
LEFT JOIN Saker s ON k.sak_id = s.id
LEFT JOIN Personer p2 ON k.person2_id = p2.id
ORDER BY k.id;

Resultatet blir som en liten sagobok, rad för rad:

PersonGörSakMottagare
Pellepantapantburknull
Kallepantapantburknull
PelleköpadockaMaria
KalleköpadockaMaria
PellegedockaMaria
KallegedockaMaria
Mariaätatårtanull
Mariaätatårtanull
Pelleätatårtanull
Kalleätatårtanull

Olika sorters JOINs, olika sorters sagor

  • INNER JOIN: Visar bara de perfekta händelserna där alla delar finns med: en person, en handling och en sak. Den skulle till exempel bara visa när Pelle köper dockan, men inte när han bara pantar (om vi ansåg att “panta” inte har en mottagare). Den är lite kräsen och vill att alla roller ska vara besatta.
  • LEFT JOIN: Berättar historien från vänster till höger. Den tar med allt från den första tabellen (vår Koppling-tabell) och försöker hitta matchningar i de andra. Om en händelse inte har en mottagare (som när någon äter tårta) lämnas den platsen bara tom. Den är förlåtande och ser till att ingen del av handlingen glöms bort.
  • CROSS JOIN: Rena kaoset! Tänk dig att alla personer i sagan plötsligt gör alla händelser med alla saker, samtidigt. Maria äter en pantburk, Pelle ger sig själv en tårta, och Kalle köper Maria. Ett fullständigt tårtkalas utan slut där alla regler har kastats ut genom fönstret. Används sällan, men är kul att fantisera om.
-- Exempel på INNER JOIN för att se vem som köpte vad till vem.
-- Här visas bara rader där det finns en köpare, en vara OCH en mottagare.
SELECT p1.namn AS Köpare, s.namn AS Vara, p2.namn AS Till
FROM Koppling k
INNER JOIN Personer p1 ON k.person1_id = p1.id
INNER JOIN Saker s ON k.sak_id = s.id
INNER JOIN Handelser h ON k.handelse_id = h.id
INNER JOIN Personer p2 ON k.person2_id = p2.id
WHERE h.handelse = 'köpa';

Och så levde Maria, Pelle och Kalle lyckliga i sin databas alla sina dagar… Tills någon råkade skriva:

DROP TABLE Saker;

…och plötsligt fanns varken docka, tårta eller pantburkar kvar i sagan. Men det är ett helt annat, och mycket sorgligare, kapitel. 😉


Upp

Upp


Licens: Apache 2.0 | © 2023 Marcus Medina, Campus Mölndal. Alla rättigheter förbehållna.
Du får använda och modifiera detta verk enligt villkoren i Apache License, Version 2.0. Du får inte använda detta verk för kommersiella ändamål utan tillstånd från upphovsmannen.