Tore Mallaug 6.11.2007 Opphavsrett: Forfatter og Stiftelsen TISIP Lærestoffet er utviklet for fagene LN323D Databaser 1. Resymé: Denne leksjonen viser et eksempel på normalisering av en liten database. Databasen dekomponeres til et sett med tabeller som tilfredsstiller BCNF. Leksjonen bør leses sammen med kapittel 3 i boka Databaser. Innhold 1.1. KOMMENTARER TIL LÆREBOKA... 1 1.2. EKSEMPEL : TABELL FOR TIMEAVTALER... 2 1.3. PROBLEMER MED TABELLEN OVER... 2 1.4. FUNKSJONELLE DETERMINERINGER... 2 1.5. HVILKE NORMALFORM TILFREDSSTILLER TABELLEN?... 3 1.6. DEKOMPONERING TIL BCNF... 4 1.7. SJEKKE OM RESULTATET ER TAPLØST-JOIN... 5 1.1. Kommentarer til læreboka Les igjennom hele kapittel 3. Alt stoffet like viktig. Leksjonen supplerer med et eksempel. Se også gamle eksamensoppgaver på web for flere eksempler.
1.2. Eksempel : tabell for timeavtaler Tabellen under brukes for å lagre timeavtaler ved et legesenter. En pasient for tildelt en time hos en lege på en bestemt dag (dato) og tidspunkt. I tillegg registreres behov for for timen - normalt legekontoret (konsultasjon), men senteret har også eget behandlings for enkle kirurgiske inngrep. En lege vil ikke utføre både konsultasjoner og kirurgi på samme dag. legenavn pasient nr pasientnavn dag tid behandling L100 Ole Aas P100 Gro Hansen 12.09.03 10.00 konsultasjon k10 L100 Ole Aas P105 Per Olsen 12.09.03 12.00 konsultasjon k10 L102 Eva Moe P106 Gunnar Gran 12.09.03 10.00 konsultasjon k11 L110 Lise Berg P108 Hege Hansen 13.09.09 10.00 konsultasjon k12 L102 Eva Moe P106 Gunnar Gran 23.09.03 09.00 kirurgisk b01 Oppgave: (1)Forklar hvilke problemer som kan oppstå ved bruk av tabellen. (2) Finn funksjonelle determineringer. (3) Hvilken normalform tilfredsstiller tabellen? (4) Dekomponer tabellen til BCNF. (5) Sjekk at resultatet på BCNF tilfredsstiller tapløst-join -egenskapen 1.3. Problemer med tabellen over På grunn av redundans (dobeltlagring) i tabellen, vil det forekomme problemer ved både innsetting, sletting og oppdatering. F.eks. for data om en lege ( og legenavn) har vi følgende problemer: Innsetting - Data om en lege kan ikke lagres uten at det finnes en pasient som har en timeavtale med denne legen. Problemet kan evt. løses ved å bruke NULL-verdier i tabellen, men det er dårlig databasedesign. Sletting - Dersom alle timeavtalene til legen slettes, slettes også og legenavn til legen! Referanseintegritetsreglene (omtalt i forrige leksjon) klarer ikke å fange opp dette problemet her. Oppdatering (endring) Hvis en lege endrer navn, må attributten legenavn oppdateres for samtlige timebestillinger denne legen har. Dette skaper unødvendig merarbeid. 1.4. Funksjonelle determineringer I arbeidet med å normalisere tabellen, må vi finne de funksjonelle determineringene. Vi forutsetter da at og pasientnr er entydige i den forstand at en lege kun har ett, mens en pasient kun har ett pasientnr. Merk deg at verken, pasientnr, eller kombinasjonen av dem er noe mulig primærnøkkel i tabellen. En lege kan ha flere pasienter, en pasient kan ha flere side 2 av 5
timebestillinger, typisk hos samme lege men ikke nødvendigvis. Følgelig er ingen av disse entydige i tabellen. Vi konsentrere oss om å finne de funksjonelle determineringene. Her er noen mulige: fd1 legenavn fd2 pasientnr pasientnavn fd3 behandling fd4 dag Har kalt disse fire funksjonelle determineringene for fd1,, fd4. fd3 forutsetter at kun en type behandling kan foregå på et, og at -attributtet er entydig slik at to ulike ikke har den samme koden. fd4 forutsetter at en lege kun tar i mot pasienter på ett bestemt på en gitt dato/dag. Merk deg at funksjonelle determineringer ikke er et spørsmål om matematikk, men om den semantiske (konseptuelle) forståelsen av den virkeligheten tabellen lagrer data om. Derfor er det hvilke forutsetninger vi legger til grunn som bestemmer determineringene. Merk deg også: Hvis en designer tabeller ut fra en datamodelleringsprosess i ER-modellen, vil man ofte få mer eller mindre normaliserte tabeller som resultat. Datamodellering vil derfor være et alternativ til omfattende dekomponeringer av store tabeller. 1.5. Hvilke normalform tilfredsstiller tabellen? Dersom vi forutsetter at alle attributtene kun inneholder enkeltverdier, eller atomiske verdier, er tabellen på 1NF. (Et alternativ her kunne vært å splitte opp både legenavn og pasientnavn i to nye attributt for fornavn og etternavn, men vi antar dette ikke er nødvendig i denne databasen). side 3 av 5
For at tabellen skal tilfredsstille 2NF må primærnøkkelen (og evt. kandidatnøkler) determinere de resterende attributtene i tabellen (se læreboka s. 81-82). Ut fra de funksjonelle determineringene over, er den eneste (minimale) nøkkelen i tabellen den sammensatte nøkkelen: (, pasientnr, dag, tid) Hvis 2NF så må alle de andre attributtene i tabellen determineres av hele denne nøkkelen. fd1, fd2 og fd4 viser at dette ikke er tilfelle, siden alle disse vil være partielle determineringer. Kan vises slik: dag tid pasientnr legenavn pasientnavn behandling Merk deg! Siden tabellen ikke er på 2NF, er den heller ikke på 3NF eller BCNF. Svaret blir derfor at tabellen kun er på 1NF. 1.6. Dekomponering til BCNF For å få en løsning på 2NF kan vi dekomponere etter fd1, fd2 og fd4. Vi får da fire tabeller: TIMEBESTILLING (, pasientnr, dag, tid) LEGE (, legenavn) PASIENT (pasientnr, pasientnavn) LEGE_ROM (, dag,, behandling) Understrekne attributter er valgt primærnøkkel. Tabellen LEGE_ROM tilfredsstiller imidlertid ikke 3NF. fd3 gir en transitiv determinering, siden determinerer behandling. Vi dekomponerer derfor videre ved å lage en ny tabell samt ta vekk behandling i LEGE_ROM: LEGE_ROM (, dag, ) ROM_BEHANDLING (, behandling) side 4 av 5
For å sjekke BCNF kan vi først eliminere vekk tabeller med kun to attributt (her LEGE, PASIENT og ROM_BEHANDLING), siden slike tabeller alltid tilfredsstiller BCNF. Vi står da igjen med å sjekke BCNF for TIMEBESTILLING og LEGE_ROM. Vi må lete etter kandidatnøkler i disse. Vi finner ingen interessante, gitt at flere leger kan oppholde seg på samme på samme dag. Dette eliminerer vekk (dag, ) som mulig nøkkel i LEGE_ROM. Uten mulige kandidatnøkler må BCNF være innfridd. De endelige tabellene blir da: TIMEBESTILLING (*, pasientnr*, dag*, tid) LEGE (, legenavn) PASIENT (pasientnr, pasientnavn) LEGE_ROM (*, dag, *) ROM_BEHANDLING (, behandling) Attributter merket * er fremmednøkler. 1.7. Sjekke om resultatet er tapløst-join Såkalt tapløs dekomponering er overfladisk nevnt i kap. 3.7 i læreboka. I praksis betyr dette at alle de små tabellene i resultatet etter dekomponeringen må kunne forenes (eng. join) slik at vi får tilbake tabellen vi hadde før normaliseringen. Hvis dette er mulig vet vi at vi ikke har mistet noe (semantisk) informasjon under dekomponeringen. Alle tabellene over kan forenes, f.eks. slik (viser dette med notasjonen fra relasjonsalgebraen i kap. 2): JOIN(LEGE_ROM:::, ROM_BEHANDLING:::, R1::); JOIN(R1:::(,dag), TIMEBESTILLING::(,dag), R2::); JOIN(R2:::, LEGE:::, R3::); JOIN(R3:::pasientnr, PASIENT:::pasientnr, R4::); Relasjon R4 er lik den opprinnelige tabellen. side 5 av 5