Design af databaser

Opgaver
1. Tabeller
Relation En database består af en række af tabeller, der indeholder data. Det er grundlæggende den måde hvorpå man opbygger en relationel database. Man kalder også en tabel for en relation (her af navnet "relationel database"), da den beskriver en sammenhæng mellem en række af data (i.e. attributter).
Kardinalitet Hvis vi f.eks. har en tabel med oplysninger om personer — en person-tabel — vil hver række i tabellen indeholde oplysninger om én person, og antallet af rækker i tabellen, vil være lig antallet af personer som optræder i tabellen. Antallet af rækker i en tabel kaldes dens kardinalitet. Der kan ikke optræde to rækker i en tabel, der er helt ens — der må mindst være én attribut-værdi, der adskiller to rækker fra hinanden. Dette er mængde-egenskaben ved rækker i tabeller — at der kun være en forekomst af hvert element (her er ét element lig med én række).
Navn Alle tabeller har et navn, der bruges til at referere til dem. Som vi skal se i et senere kapitel, bruger vi SQL til at manipulere relationelle databaser. SQL er ikke case-sensitive (skelner ikke mellem store og små bogstaver) og spørgsmålet om man anvender camel-notation eller ej, har derfor kun kosmetisk betydning ved navngivning, og håndhæves ikke. Måske pga. det, eller fordi relationelle databaser og SQL blev udviklet i 70'erne, ser man ofte underscore ('_') anvendt, når et navn er sammensat af flere ord.
  1.1 Attributter
Tupler, attributter og kollonner Som sagt består en tabel af rækker, der f.eks. beskriver de enkelte personer i en person-tabel. Man kalder også en række for et tuppel. Hvis vi om hver person registrerer navn, samt adressen med gade, nr, post-nummer, og alder, vil der være fem forskellige oplysninger registreret om hver person i tabellen. Man kalder de enkelte oplysninger attributter, og vores tabel har derfor fem attributter. Hver attribut svarer til én kolonne i tabellen, og vores tabel har derfor fem kolonner.
Værdimængde Hver attribut har en værdimængde, der afgør hvilke værdier attributten kan antage. En attribut må kun antage én af værdimængdens værdier af gangen, og den kan derfor ikke være en liste af værdier. Dette er en egenskab vi vender tilbage til i forbindelse med normalisering.
2. Nøgler
  Meget af arbejdet med databaser, drejer sig om at udvælge bestemte rækker efter et eller andet kriterie. Det kan være vi søger personer, der bor på en bestemt adresse, eller vi vil ændre adressen på en bestemt person.
Kandidatnøgler Hvis vi vil udpege en bestemt række i en tabel, har vi brug for noget der er uniquet for den pågældende rækker, så vi ikke risikerer at blande det vi gør, sammen med andre rækker. I Danmark har vi alle et CPR-nummer, der entydigt identificerer en enkelte person, men det er kun i få lande man har det. I database-sammenhæng, vil man ikke så sjældent have brug for at indføre en entydig identifkation af hver række, fordi der ikke findes en velegnet attribut til formålet, blandt de attributter, der allerede findes i tabellen. En sådan attribut kalder man ofte id, eller variationer over dette navn. Inden man vælger at indføre en sådan ny attribut, søger man først blandt de allerede eksisterende attributter. Hvis man blandt disse finder en eller flere kandidater, betegnes disse kandidatnøgler. Deres værdier skal som sagt være unique for hver række, men findes der ikke en sådan attribut, kan flere attributter til sammen måske entydigt udpege rækkerne.
Sammensat nøgle Hvis vi f.eks. har registreret telefon-nummeret i en kunde-tabel, vil dette ikke helt entydigt kunne udpege den enkelte kunder, da flere personer i samme husstand kan have samme fastnet-nummer. Kombinerer vi det med navn kan dette entydigt udpege den enkelte kunde, da to personer i samme husstand næppe har det samme (fulde) navn. Det at vi kombinerer to (eller flere) attrbutter for at opnå en entydig identifikation af hver enkelt række, kades en sammensat nøgle. Vi kunne derfor have en sammensat nøgle bestående af: telefon_nummer og navn. I praksis vil denne sammensatte nøgle være for dårlig, da vi ikke med absolut sikkerhed kan regne med, at to personer i samme husstand ikke har samme navn — men for eksemplets skyld!
Primærnøgle Vi udvælger en nøgle blandt kandidatnøglerne og udpeger den som værende den vi vil bruge. Denne kandidatnøgle forfremmes til at være primærnøgle. Vi vil ikke anvende de andre kandidatnøgler til entydigt at udpege rækker, da det skaber forvirring omkring hvad vi bruger, og primærnøglen spiller samtidig en særlig rolle for tabellen, når vi senere skal til at normalisere vores database.
Fremmednøgle Der findes en tredie form for nøgle: fremmednøgler. Fremmednøgler er attributter, der har værdier som er hentet fra primærnøgler i en anden tabel. Disse nøgler skaber en sammenhæng mellem tabeller, vi skal studere nærmere i næste afsnit.
3. Referentiel integritet
Reference fra fremmednøgle til primærnøgle En tabel er en relation, idet den beskriver en relation mellem de attributter, der optræder i tabellen. Men der er også relationer mellem tabeller. Disse relationer består hver især af en fremmednøgle i en tabel, der refererer til en primærnøgle i en anden tabel. Den referentielle integritet i en database, er spørgsmålet om man kan regne med disse referencer. Om man faktuelt kan regne med de data der optræder i databasen (e.g. om det passer, at Anders And bor på Paradisæblevej), er ikke et spørgsmål vi beskæftiger os med i forbindelse med database design. Og spørgsmålet om vi kan regne med referencerne, er derfor et rent teknisk spørgsmål: Om fremmednøglerne refererer til primærnøgler, der rent faktisk eksisterer (e.g. når Anders And's postnummer er 7430, findes dette postnummer så i postnummer-tabellen?).
Ændring og sletning Denne sammenhæng i databasen er afgørende for at man kan arbejde med den, ellers kan man ikke lave data-udtræk, der anvender reletioner mellem tabeller. Den manglende sammenhæng kan i primcippet opstå ved indsættelse, men den reelle bekymring retter sig imod ændring og sletning af rækker i databasen.
Hvornår er der et problem? Da referencen mellem tabeller består af fremmednøgler der refererer til primærnøgler, ligger faren i primærnøglerne — når man ændrer (i.e. ændring der indbefatter ændring af primærnøglen) eller sletter rækker, hvis primærnøgle danner grundlag for en relationen mellem tabellerne. Hvis man har en primærnøgle som ingen anden tabel refererer til, er der aldrig noget problem! Hvis man derimod har en primærnøgle i en tabel som en anden tabels fremmednøgle refererer til, kan der være et problem — det afhænger af om den konkrete primærnøgle-værdi optræder som fremmednøgle-værdi i en tabel der refererer til primærnøglen (e.g. om sletning af rækken med postnummeret 7430 (i.e. Ikast) i postnummer-tabellen giver problemer, afhænger af om der i person-tabellen er rækker hvor fremmednøglen: post_nummer rent faktisk har værdien: 7430. Hvis der ikke er registreret nogen personer, der bor i Ikast, er der ikke noget problem!).
  Hvad gør man så når der er et problem? Der er flere muligheder:
  Restrict
Nægter at foretage ændring eller sletning Med restrict nægter man at foretage den ændring eller sletning, der ønskes udført. Det checkes om primærnøgle-værdien i den række man ønsker ændret eller slettet, svarer til en fremmednøgle-værdi i en tabel der refererer til den. Hvis det er tilfældet udføres operationen ikke! Man kunne f.eks. forestille sig, at der blev kastet en exception eller lign. i forbindelse med den fejlslagne operation.
  Når en sådan operation er blevet afvist af databasen, er det så op til den del af systemet der har ønsket operationen udført, at forholde sig til det. Det kan være at den use case operationen indgår i helt må opgives. Det kan også være at der må foretages en række indlednede operationer der muliggør det ønskede (e.g. ændring eller sletning af de rækker, der indeholder fremmednøgle-vædier, der forhindrer operationens udførelse).
  Cascade
  Med cascade lader man konsekvenserne af en ændring eller sletning sprede sig til andre tabeller i databasen.
Ændrer også fremmednøgle Ved ændring af en primærnøgle-værdi, må de fremmednøgle-værdier, der refererer til primærnøglen tilsvarende ændres. På denne måde kan en ændring ved cascade brede sig fra en tabel til en anden, men ikke længere, da der i den anden tabel ikke er tale om en primærnøgle, men en fremmednøgle. Hvis vi f.eks. har en postnummer-tabel, og i denne tabel ændrer primær-nøglen: nr, for et postdistrikt (e.g. ændrer postnummeret for Ikast, fra 7430 til 7474), vil cascade foretage en tilsvarende ændring i alle tabeller, hvor dette postnummer optræder som fremmednøgle.
Sletter rækker i andre tabeller Ved sletning bliver de rækker i andre tabeller, der med deres fremmednøgle-værdier, refererer til primærnøgle-værdien i den række der skal slettes, og så selv slettet! Hvis vi f.eks. igen har en postnummer-tabel, og denne gang sletter en række med et postdistrikt (e.g. sletter Ikast postdistrikt), vil cascade slette alle rækker i andre tabeller, hvor postnummeret optræder som fremmednøgle (e.g. slette alle personer, der er registreret som bosiddende i Ikast, fra databasen). En sådan sletning kan sprede sig rundt i databasens tabeller, da hver række der slettes, har sin egen primærnøgle.
  Set to null
En mellemting Vi har nu set to muligheder, den første (Restrict) afviser at foretage ændringer, hvis der refereres til primærnøglen, den anden (Cascade) fjerner alt, hvad der direkte eller indirekte refererer til den. Potentielt set to drastiske reaktioner! Den tredie vi skal se, accepterer at foretage ændringen, men den begrænser samtidig dens konsekvenser.
  Når en fremmednøgle-værdi refererer til en primærnøgle-værdi, der enten bliver ændret eller slettet (i.e. dens række bliver slettet), bliver fremmednøglen sat til null. Det er en angivelse af at fremmednøglen ikke (længere) refererer til noget, en betydning man kender fra programmering.
4. Multiplicitet
  Vi har nu beskæftiget os en del med de relationer, der kan være mellem tabeller. De består af en fremmednøgle, der refererer til en primærnøgle. Primærnøglerne er unique, men man kan udemærket have flere fremmednøgler med samme værdi, idet de derved refererer til samme primærnøgle. Det betyder, at en eller flere rækker i tabellen med fremmednøglen kan referere til én række i den tabel der har primærnøglen. Dette gør det muligt at etablere en-til-en og en-til-mange relationer.
  4.1 En-til-en relationer
Unique fremmed­nøgler, Samle tabeller En en-til-en relation er hvor fremmednøglerne er unique — hvor (højest) én række i fremmednøgle-tabellen refererer til hver række i primærnøgle-tabellen. Hvis der vitterlig vil være en fremmednøgle for hver primærnøgle, kan det være nærliggende at samle de to tabeller, da rækkerne i de to tabeller vil høre parvis sammen. Det er dog også muligt at fremmednøgle-tabellen vil indeholde færre rækker end primærnøgle-tabellen, idet visse af primærnøglerne ikke vil have tilhørende rækker i fremmednøgle-tabellen. Hvis man i denne situation vælger at samle de to tabeller, må man indføre null-værdier i forbindelse med de rækker, der mangler i fremmednøgle-tabellen — ikke en god løsning, og også grunden til at man nogen gange ser en-til-en relationer i databaser.
  4.2 En-til-mange relationer
Mange fremmed­nøgler til en primær­nøgle En-til-mange relationer, er de mest naturlige relationer for fremmed- og primærnøgler. At flere fremmednøgle-værdier kan være ens, og dermed referere til den samme række i fremmednøgle-tabellen. Da det er fremmednøglen, der refererer til primærnøglen, var det måske mere logisk at kalde disse relationer mange-til-en relationer, idet mange fremmednøgler kan referere til en primærnøgle — men traditionen er en anden.
  4.3 Mange-til-mange relationer
Ikke uden videre Man kan ikke uden videre lave mange-til-mange relationer i en database. Mens man arbejder med relationerne mellem de entiteter der skal repræsenteres i databasen, kan det være helt naturligt og uden problemer at arbejde med mange-til-mange relationer, men i det øjeblik man skal til at realisere dem i database designet, har man problemet.
Dårligt med liste af fremmednøgler Skulle man umiddelbart lave mange-til-mange relationer i en database, skulle det ske ved at man lod attributterne indeholde en liste af fremmednøgler, der kunne referere til primærnøgler i en anden tabel. Idéen med at lade attributter indeholde lister er dårlig, den er meget besværlig at arbejde med, og den er den første dårligdom der bliver fjernet når man begynder at normalisere — så, hvad gør man så?
  [Ikke skrevet færdig]
5. Normalisering
Normalformer, Der stilles flere og flere krav Der findes en lang række af normalformer, der er nummereret fra 1. normalform (1NF) og opefter. For alle normalformer gælder der, at de stiller et eller flere krav til databasens design. For x'te normalform gælder der, at den samtidig kræver at databasen er på (x-1)'te normalform — f.eks. kræver 3. normalform at databasen også er på 2. normalform. På denne måde, bygger en normalform reelt ovenpå alle de foregående, og der stilles derfor flere og flere krav til at databasen befinder sig på den pågældende normalform. At omforme databasens design så den opfylder en given normalform, kaldes: at normalisere. Vi skal i dette afsnit se på de første tre normalformer, og hvordan man i den forbindelse kan normalisere en database.
  5.1 Hvorfor normalisere?
  Iden vi gør os den ulejlighed at normalisere en database til en given normalform, kunne man spørge: Hvorfor gør vi det? Hvad vil vi opnå ved at normalisere?
  Vi ønsker at opnå en række kvaliteter ved databasens design:
  5.1.1 Fjerne redundans
Overflødigt, Unødvendigt Noget der er redundant, er noget der er overflødigt. I database-sammenhæng er redundans, at de samme data optræder flere gange. Man kan ikke helt undgå at de samme data optræder flere gange — det gør sig gældende for fremmednøgler, der nødvendigvis må antage de samme værdier som primærnøgler, for at skabe sammenhæng mellem tabeller i databasen. Man kan derfor sige at redundans er, at de samme data unødvendigt optræder flere gange i databasen.
  Enhver form for redundans er spild af plads, og det er det også i forbindelse med databaser, men hvilke andre problemer kan redundans ellers afstedkomme?
  [Ikke skrevet færdig]
  5.1.2. Minimere brug af null-værdier
  [Ikke skrevet færdig]
  5.1.3 Undgå tab af information
  [Ikke skrevet færdig]
  5.1.4 Hvorfor ikke normalisere?
  [Ikke skrevet færdig]
  5.2 Første normalform
  [Ikke skrevet færdig]
  5.2 Anden normalform
  [Ikke skrevet færdig]
  5.3 Tredie normalform
  [Ikke skrevet færdig]
  5.4 Andre normalformer
  [Ikke skrevet færdig]