Forstå relasjonsdatabasemodellen, fremmednøkler, relasjonstyper og ER-diagrammer.
Relasjonsdatabaser og datamodellering
I forrige kapittel ble vi kjent med grunnleggende databasebegreper. Nå skal vi dykke dypere inn i relasjonsdatabasemodellen – den modellen som ligger til grunn for de fleste databaser i verden. Vi skal lære hvordan tabeller kobles sammen, hvilke typer relasjoner som finnes, og hvordan vi planlegger en database ved hjelp av ER-diagrammer.
God datamodellering er noe av det viktigste du kan lære om databaser. En godt designet database er enkel å jobbe med, rask å søke i og lett å utvide. En dårlig designet database fører derimot til dupliserte data, inkonsistens og ytelsessproblemer som er vanskelige å rette opp i etterkant. Derfor bruker man alltid tid på å planlegge databasestrukturen grundig før man begynner å lage tabeller og fylle inn data.
En fremmednøkkel er en kolonne i en tabell som inneholder verdier som refererer til primærnøkkelen i en annen tabell. Fremmednøkler er limet som holder en relasjonsdatabase sammen – de oppretter koblinger mellom tabeller. Fremmednøkler sikrer referanseintegritet, som betyr at databasen hindrer deg i å opprette referanser til rader som ikke eksisterer. For eksempel kan du ikke registrere en karakter for elev_id 99 hvis det ikke finnes noen elev med id 99 i elevtabellen.
Det finnes tre grunnleggende typer relasjoner mellom tabeller i en relasjonsdatabase:
1. En-til-en (1:1)
Hver rad i tabell A er koblet til nøyaktig én rad i tabell B, og omvendt. Denne typen er relativt sjelden.
Eksempel: Hver elev har nøyaktig ett elevkort, og hvert elevkort tilhører nøyaktig én elev.
| elevid | fornavn | etternavn | → | kortid | elevid | kortnummer | utstedtdato |
|---|---|---|---|---|---|---|---|
| 1 | Emma | Hansen | 1 | 1 | EK-2024-001 | 2024-08-15 | |
| 2 | Oliver | Johansen | 2 | 2 | EK-2024-002 | 2024-08-15 |
2. En-til-mange (1:N)
Én rad i tabell A kan kobles til mange rader i tabell B, men hver rad i tabell B kobles til bare én rad i tabell A. Dette er den vanligste relasjonstypen.
Eksempel: Én klasse har mange elever, men hver elev tilhører bare én klasse.
| klasseid | klassenavn | → | elevid | fornavn | klasseid |
|---|---|---|---|---|---|
| 1 | 10A | 1 | Emma | 1 | |
| 2 | 10B | 2 | Oliver | 1 | |
| 3 | Nora | 2 |
Fremmednøkkelen klasse_id ligger på mange-siden (i elevtabellen).
3. Mange-til-mange (M:N)
Mange rader i tabell A kan kobles til mange rader i tabell B. Denne relasjonstypen krever alltid en koblingstabell.
Eksempel: En elev kan ha mange fag, og et fag kan ha mange elever.
Denne relasjonen kan ikke løses med bare en fremmednøkkel – vi trenger en koblingstabell mellom de to:
elever ← elevfag → fag
La oss se på forholdet mellom elever og fag:
Tabell: elever
| elevid | fornavn | etternavn |
|---|---|---|
| 1 | Emma | Hansen |
| 2 | Oliver | Johansen |
| 3 | Nora | Olsen |
Tabell: fag
| fagid | fagnavn |
|---|---|
| 1 | Matematikk |
| 2 | Norsk |
| 3 | Naturfag |
Koblingstabell: elevfag
| elevid | fagid |
|---|---|
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 2 | 1 |
| 2 | 2 |
| 3 | 2 |
| 3 | 3 |
Her kan vi lese at:
- Emma (elevid 1) tar matematikk, norsk og naturfag
- Oliver (elevid 2) tar matematikk og norsk
- Nora (elevid 3) tar norsk og naturfag
Koblingstabellen har en sammensatt primærnøkkel bestående av begge fremmednøklene (elev_id + fag_id). Den kan også utvides med ekstra kolonner, for eksempel karakter eller termin.
Før du oppretter en database, bør du planlegge strukturen visuelt. Et ER-diagram (Entity-Relationship-diagram) er et standardverktøy for dette. ER-diagrammer viser:
- Entiteter (ting vi lagrer informasjon om) som rektangler
- Attributter (egenskaper) som ovaler koblet til entiteten
- Relasjoner som linjer mellom entiteter med markeringer for relasjonstype
Kråkefotsnotasjon (Crow's Foot)
Den mest brukte notasjonen for ER-diagrammer i praksis er kråkefotsnotasjon. Her brukes symboler på linjene mellom tabellene:
- | (strek) = nøyaktig én
- O (sirkel) = null (valgfri)
- < (kråkefot/gaffel) = mange
Kombinasjoner:
- ||——|| = en-til-en (begge obligatoriske)
- ||——O< = en-til-mange (mange-siden er valgfri)
- ||——|< = en-til-mange (mange-siden er obligatorisk)
- >O——O< = mange-til-mange (begge sider valgfrie)
Eksempel: ER-diagram for skoledatabase
┌──────────┐ ┌──────────┐
│ Klasse │ 1 N │ Elev │
│──────────│─────────│──────────│
│ klasse_id│ │ elev_id │
│ navn │ │ fornavn │
└──────────┘ │ etternavn│
│ klasse_id│
└──────────┘
│
│ N
┌──────────┐
│ Elev_Fag │
│──────────│
│ elev_id │
│ fag_id │
│ karakter │
└──────────┘
│
│ N
┌──────────┐
│ Fag │
│──────────│
│ fag_id │
│ fagnavn │
│ laerer │
└──────────┘Her ser vi at Klasse har en en-til-mange-relasjon med Elev (én klasse har mange elever), og Elev har en mange-til-mange-relasjon med Fag (via koblingstabellen Elev_Fag).
Når vi har planlagt databasestrukturen, er neste steg å opprette tabellene med SQL. Kommandoen CREATE TABLE brukes til å definere en ny tabell med kolonner, datatyper og begrensninger.
Her er SQL-koden for skoledatabasen:
-- Opprett tabellen for klasser
CREATE TABLE klasser (
klasse_id INTEGER PRIMARY KEY AUTOINCREMENT,
klassenavn TEXT NOT NULL
);
-- Opprett tabellen for elever
CREATE TABLE elever (
elev_id INTEGER PRIMARY KEY AUTOINCREMENT,
fornavn TEXT NOT NULL,
etternavn TEXT NOT NULL,
fodselsdato DATE,
klasse_id INTEGER,
FOREIGN KEY (klasse_id) REFERENCES klasser(klasse_id)
);
-- Opprett tabellen for fag
CREATE TABLE fag (
fag_id INTEGER PRIMARY KEY AUTOINCREMENT,
fagnavn TEXT NOT NULL,
laerer TEXT
);
-- Opprett koblingstabellen for elever og fag
CREATE TABLE elev_fag (
elev_id INTEGER,
fag_id INTEGER,
karakter INTEGER,
termin TEXT,
PRIMARY KEY (elev_id, fag_id),
FOREIGN KEY (elev_id) REFERENCES elever(elev_id),
FOREIGN KEY (fag_id) REFERENCES fag(fag_id)
);La oss bryte ned de viktigste elementene:
- INTEGER PRIMARY KEY AUTOINCREMENT – Oppretter en primærnøkkel som automatisk øker med 1 for hver ny rad
- TEXT NOT NULL – Kolonnen lagrer tekst og kan ikke være tom
- FOREIGN KEY ... REFERENCES ... – Oppretter en fremmednøkkel som refererer til en annen tabell
- PRIMARY KEY (elev_id, fag_id) – Sammensatt primærnøkkel som sikrer at kombinasjonen av elev og fag er unik
La oss modellere en enkel nettbutikk med kunder, produkter og bestillinger.
Entiteter og attributter:
- Kunde: kundeid, fornavn, etternavn, epost, telefon
- Produkt: produktid, produktnavn, beskrivelse, pris, antallpaalager
- Bestilling: bestillingid, kundeid, bestillingsdato, totalpris, status
- Bestillingslinje: bestillingid, produktid, antall, linjepris
Relasjoner:
- Kunde → Bestilling: En-til-mange (én kunde kan ha mange bestillinger)
- Bestilling → Bestillingslinje: En-til-mange (én bestilling kan ha mange produkter)
- Produkt → Bestillingslinje: En-til-mange (ett produkt kan være i mange bestillinger)
CREATE TABLE kunder (
kunde_id INTEGER PRIMARY KEY AUTOINCREMENT,
fornavn TEXT NOT NULL,
etternavn TEXT NOT NULL,
epost TEXT UNIQUE NOT NULL,
telefon TEXT
);
CREATE TABLE produkter (
produkt_id INTEGER PRIMARY KEY AUTOINCREMENT,
produktnavn TEXT NOT NULL,
beskrivelse TEXT,
pris REAL NOT NULL,
antall_paa_lager INTEGER DEFAULT 0
);
CREATE TABLE bestillinger (
bestilling_id INTEGER PRIMARY KEY AUTOINCREMENT,
kunde_id INTEGER NOT NULL,
bestillingsdato DATE DEFAULT CURRENT_DATE,
totalpris REAL,
status TEXT DEFAULT 'ny',
FOREIGN KEY (kunde_id) REFERENCES kunder(kunde_id)
);
CREATE TABLE bestillingslinjer (
bestilling_id INTEGER,
produkt_id INTEGER,
antall INTEGER NOT NULL,
linjepris REAL NOT NULL,
PRIMARY KEY (bestilling_id, produkt_id),
FOREIGN KEY (bestilling_id) REFERENCES bestillinger(bestilling_id),
FOREIGN KEY (produkt_id) REFERENCES produkter(produkt_id)
);Her ser vi mange-til-mange-relasjonen mellom bestillinger og produkter løst gjennom koblingstabellen bestillingslinjer. En bestilling kan inneholde mange produkter, og et produkt kan inngå i mange bestillinger.
Begrensninger (constraints) er regler du kan legge på kolonner for å sikre datakvalitet:
- PRIMARY KEY – Kolonnen er primærnøkkel (unik og ikke NULL)
- NOT NULL – Kolonnen kan ikke være tom
- UNIQUE – Alle verdier i kolonnen må være unike
- DEFAULT verdi – Gir kolonnen en standardverdi hvis ingen verdi oppgis
- CHECK (betingelse) – Verdien må oppfylle en betingelse (f.eks. CHECK (alder >= 0))
- FOREIGN KEY – Verdien må eksistere som primærnøkkel i en annen tabell
Begrensninger er viktige fordi de sikrer at dataene i databasen alltid er gyldige og konsistente, uavhengig av hvem eller hva som setter inn data.
Unngå disse vanlige feilene når du designer en database:
1. Alt i én tabell: Ikke legg all informasjon i én stor tabell. Del opp i logiske enheter.
2. Glemme primærnøkkel: Hver tabell bør alltid ha en primærnøkkel.
3. Bruke navn som primærnøkkel: Navn er ikke unike – bruk et generert ID-nummer.
4. Lagre beregnede verdier: Ikke lagre data som kan beregnes (f.eks. alder fra fødselsdato).
5. Glemme fremmednøkler: Definer alltid fremmednøkler eksplisitt for å sikre referanseintegritet.
6. Inkonsistente datatyper: Bruk alltid samme datatype for kolonner som skal sammenlignes.
Følg disse stegene når du skal designe en ny database:
1. Identifiser entitetene – Hva trenger du å lagre informasjon om? (Elever, bøker, bestillinger...)
2. Definer attributtene – Hvilke egenskaper har hver entitet? (Navn, pris, dato...)
3. Bestem primærnøkler – Hva identifiserer hver rad unikt?
4. Finn relasjonene – Hvordan henger entitetene sammen? (En-til-mange, mange-til-mange?)
5. Tegn ER-diagram – Lag en visuell oversikt over strukturen
6. Skriv CREATE TABLE – Opprett tabellene med SQL
7. Test med data – Sett inn noen testrader og verifiser at alt fungerer
Hva er en fremmednøkkel?
Hvilken relasjonstype finnes mellom tabellene «klasser» og «elever» hvis hver elev tilhører nøyaktig én klasse, men en klasse kan ha mange elever?
Hvordan implementeres en mange-til-mange-relasjon i en relasjonsdatabase?
Gitt følgende SQL:
CREATE TABLE elever (
elev_id INTEGER PRIMARY KEY AUTOINCREMENT,
fornavn TEXT NOT NULL,
etternavn TEXT NOT NULL,
klasse_id INTEGER,
FOREIGN KEY (klasse_id) REFERENCES klasser(klasse_id)
);Hva betyr NOT NULL for kolonnene fornavn og etternavn?
Tegn et ER-diagram (eller beskriv det med tekst) for en enkel kino-database. Kinoen trenger å holde oversikt over filmer (tittel, sjanger, lengde, aldersgrense), saler (salnummer, antall plasser) og forestillinger (dato, klokkeslett). Identifiser entiteter, attributter, primærnøkler og relasjoner mellom tabellene.
Skriv SQL-kode (CREATE TABLE) for kino-databasen fra forrige oppgave. Inkluder passende datatyper, primærnøkler, fremmednøkler og NOT NULL-begrensninger der det er relevant.
Du har tabellene forfattere og boker. En forfatter kan skrive mange bøker, og en bok kan ha flere forfattere (samarbeid). Hvilken relasjonstype er dette, og hvordan løses det?
Oppsummering
I dette kapittelet har du lært:
- Relasjonsmodellen: tabeller koblet med nøkler.
- Fremmednoekkel: refererer til primærnøkkelen i en annen tabell.
- Relasjonstyper: en-til-en, en-til-mange og mange-til-mange.
- Koblingstabell: løser mange-til-mange-relasjoner.
- ER-diagram: modellerer datastrukturer (kraakefotsnotasjon).
Noekkelbegreper
| Begrep | Forklaring |
|---|---|
| Fremmednoekkel | Kolonne som refererer til en annen tabells primaernoekkel |
| ER-diagram | Diagram som modellerer entiteter og relasjoner |
| Koblingstabell | Tabell som løser mange-til-mange-relasjoner |
Dette kapitlet er skrevet av Anthropics toppmodeller (Claude Opus og Claude Fable) og er foreløpig ikke manuelt gjennomgått — kvalitetskontrollen gjøres av uavhengige KI-agenter, og innmeldte feil rettes fortløpende. Funnet en feil? Meld fra, så retter vi den. Les mer om hvordan innholdet lages.