Relasjoner – OSS

Etter at jeg la ut serien med innlegg om relasjonsdatabaser her på Rosabloggen har jeg fått en del spørsmål, og jeg tenkte at det kunne være greit å samle de ofte stilte spørsmåla i et eget innlegg.

«Hva hvis en pasient har flere leger?». Det det spørres om her kalles en mange-til-mange-relasjon. I praksis betyr det at en lege kan ha mange pasienter, og en pasient kan ha mange leger. Jeg skal nå vise hvordan dette kan løses i lege/pasient-databasen vår. For at man skal ivareta normaliseringen må det innføres det som kalles en koblingstabell. For å gjøre det oversiktlig for meg selv så pleier jeg å navngi koblingstabellene med et navn som viser hvilke to tabeller jeg knytter sammen. I dette tilfellet er det tabellene «lege» og «pasient» som skal knyttes sammen i en koblingstabell, og gir den derfor enkelt og greit navnet: «lege_pasient». Koblingstabellen «lege_pasient» har det som kalles en sammensatt primærnøkkel. Den består av de to primærnøklene til tabellene «lege» og «pasient». Siden man nå ikke lenger trenger fremmednøkkelen «l_id» i tabellen «pasient» så kan denne slettes. Denne ble kun brukt til å knytte en pasient til en lege, og har derfor ingen funksjon lenger. De 3 involverte tabellene i databasen ser nå slik ut:

Under er SQL-spørringa for å hente ute en liste som viser pasienter knyttet mot leger.

SELECT pasient.navn AS pasient,
       lege.navn AS lege
  FROM pasient
  INNER JOIN lege_pasient on lege_pasient.personnr = pasient.personnr
  INNER JOIN lege on lege.l_id = lege_pasient.l_id;

Resultatet av spørringa ser slik ut:

Ser man på tabellen over så har hver lege 2 pasienter hver, og «Gunnar Åm» han har 2 leger. Nå kan det kanskje virke litt søkt at en pasient har flere leger, men mange-til-mange-relasjoner er ganske vanlig. La oss ta et enkelt ordresystem. Vi har en ordretabell og en produkttabell. Dette er en mange-til-mange-relasjon da en ordre kan inneholde mange produkter, og et produkt kan være på mange ordrer. Koblingstabellen «ordre_produkt» (et bedre navn hadde kanskje vært «ordrelinjer») vil også gjerne inneholde antallet av de respektive produktene.

«Hvordan legger jeg inn leder til en ansatt?». Der er flere måter å løse dette på. Man kunne brukt en avdelingstabell som de ansatte knyttes mot, og de ulike avdelingene har en leder knyttet mot seg. Men nå skal vi gjøre ting enklere enn som så. Problemet kan løses ved hjelp av rekursive forhold. Enkelt forklart så har man en fremmednøkkel som peker til primærnøkkelen i en og samme tabell. Jeg har laget et enkelt organisasjonskart med 10 ansatte for den fiktive bedriften Rakett AS.

Jeg har laget en enkel tabell «ansatt» for alle de ansatte. Ansattnummeret er unikt for alle ansatte i bedriften og blir primærnøkkelen «ansattnr» i tabellen «ansatt». Videre så har vi navnet og stillingen til de ansatte, og til slutt fremmednøkkelen «leder» som peker til primærnøkkelen «ansattnr» i samme tabell. Tabellen ser slik ut:

Som man ser av tabellen (og av organisasjonskart) så har alle en leder bortsett fra daglig leder. Verdien NULL betyr at der ikke eksisterer en fremmednøkkel. Skal man hente ut en liste over ledere og sine ansatte så kan SQL-spørringa skrives slik:

SELECT leder.navn AS leder,
       medarbeider.navn AS ansatt 
FROM ansatt medarbeider
INNER JOIN ansatt leder ON leder.ansattnr = medarbeider.leder;

SQL-spørringa over kalles gjerne en «self join». Man kan se på en «self join» som om at man slår sammen to kopier av samme tabell, men tabellen er selvsagt ikke kopiert. «medarbeider» og «leder» er alias til tabellen «ansatt» og navnene på de to «kopiene». Resultatet av spørringa blir som dette: