Guide: PHP- & MySQL-innføring: Kapittel 9

Databasenormalisering

Forrige gang lærte vi det mest grunnleggende om databaser. Nå skal vi sette opp databasene på best mulig måte.

Løsning

Vår løsning inneholder ingenting utover det som er definert i eksempelet, selv om det gjerne er lett for å nettopp gå utover det som er definert i eksempelet. Eksempelet i seg selv er ikke særlig realistisk; og vi skal være de første til å innrømme at vår løsning heller ikke er perfekt. Vi skal diskutere manglene i denne løsningen etter hvert. Først til presentasjonen;


Tegningen over er et såkalt entitets-relasjonsdiagram laget i verktøyet MyDBExpert. Verktøyet er ærlig talt særdeles dårlig; men det ble skrevet av undertegnede for tre år siden, og jeg er dermed særdeles fortrolig med det. Om du skal lage tilsvarende diagrammer selv, bør du nok lete deg frem til et annet alternativ. Under finnes MySQL-koden for å opprette en slik database som over.



CREATE TABLE Epost (
  PersonID INT,
  Epost VARCHAR(255) NOT NULL,
  Sted ENUM('Hjemme', 'Jobb', 'Mobil') NOT NULL,
  PRIMARY KEY (PersonID, Epost)
); # Table Epost

CREATE TABLE Telefonummer (
  PersonID INT,
  Nummer CHAR(12),
  Sted ENUM('Hjemme', 'Jobb', 'Mobil') NOT NULL,
  PRIMARY KEY (PersonID, Nummer)
); # Table Telefonummer

CREATE TABLE Poststed (
  Postnummer INT(4),
  Poststed VARCHAR(255) NOT NULL,
  PRIMARY KEY (Postnummer)
); # Table Poststed

CREATE TABLE Person (
  PersonID INT,
  Navn VARCHAR(255) NOT NULL,
  Fodselsdato DATETIME NOT NULL,
  Gate VARCHAR(255) NOT NULL,
  Postnummer INT(4) NOT NULL,
  PRIMARY KEY (PersonID)
); # Table Person

CREATE TABLE PersonligForhold (
  PersonID1 INT NOT NULL,
  PersonID2 INT NOT NULL,
  Type ENUM('Ektefelle', 'Barn', 'Foreldre', 'Venn', 'Kollega') NOT NULL,
  PRIMARY KEY(PersonID1, PersonID2)
); # Table PersonligForhold

Person-tabellen er ganske enkel, og består av ting som kun er avhengig av denne personen. Den gir også en person en unik ID som man kan bruke for å referere til denne personen i etterkant. Vi har valgt å ha to enkle tabeller for Epost og Telefonnummer; det gjør det enklere for oss å søke etter et gitt telefonnummer. Et annet alternativ ville vært å splitte Telefonnummer-tabellen i tre ulike tabeller; HjemmeTelefon, JobbTelefon og MobilTelefon. Om vi da hadde et ukjent nummer ville vi da vært nødt til å søke i tre forskjellige tabeller. I vår løsning benytter vi i stedet oss av en spesiell datatype i MySQL; ENUM, som lar deg spesifisere nøyaktig hva som kan stå i den kolonnen.

Poststed og postnummer har vi også delt ut til en egen tabell; som vi beskrev når vi snakket om tredje normalform. Vi har tatt og sett på alle typer personlige forhold i en egen tabell. Vi angir to personer på hver rad, og sier hvilket forhold disse to har. Det gir oss veldig lett alle kontaktene til en gitt person; f.eks. om vi ønsker å slå opp alle personer som begge kjenner.

Svakheter

PersonligForhold-tabellen er også vår løsnings største svakhet. Her er det vi betrakter som de to største feilene;

  • Forhold går alltid to veier, så vi må enten legge inn to rader for hvert personlige forhold (med person 1 og 2 reversert i rad 2), eller gjøre at alle spørringer tar hensyn til at person 1 og 2 kan være byttet om.

    En normalt enkel spørring for å finne ektefellen til en person går dermed fra å være;


    SELECT p.navn 
      FROM Person AS p, PersonligForhold AS f 
      WHERE f.PersonID2 = p.PersonID AND f.PersonID1 = 23 
        AND f.Type = 'Ektefelle';

    ... til å bli;


    SELECT p.Navn 
      FROM Person AS p, PersonligForhold AS f 
      WHERE f.Type = 'Ektefelle' 
        AND (
          (f.PersonID2 = p.PersonID AND f.PersonID1 = 23) 
          OR (f.PersonID1 = p.PersonID AND f.PersonID2 = 23)
        );
  • En person kan bli gift med seg selv eller være sin egen beste venn. Tabellen forhindrer oss ikke å si at en person er sitt eget barn eller at en person har flere ektefeller. Dette kunne vært delvis forhindret ved å flytte ektefelleID som et felt i Person-tabellen, og si at alle personer har et ForeldreID som peker til en annen person. Likevel stopper ikke dette tilfeller der man er sin egen beste venn, eller å si at man er gift med seg selv. Dette er mulig å løse på databasenivået ved hjelp av såkalte restriksjoner, men dette er langt utenfor hva vi kommer til å dekke i denne artikkelserien.