Documente Academic
Documente Profesional
Documente Cultură
Marin Fotache
Ca să folosesc un termen elevat şi, cu ocazia asta, să-mi descarc un pic sufletul, aşa negru
cum este el (sufletul), constat nepuntincios că am o anumită propensiune pentru subiecte
banale (pentru cei neatenţi, propensiune este termenul elevat de care vorbeam). M-a
încercat şi mă încearcă senzaţia că, alături de politică şi fotbal, la normalizarea bazelor de
date ne pricepem cu toţii. Ba chiar şi multe cărţile şi publicaţiile străine la care am avut
acces on şi off line conferă normalizării un aer de clasat, iar când e vorba de exemple,
încep a debita teoreme şi demonstraţii…
Mă intrigă şi amuză faptul că, mai întotdeauna, atunci când am fost pus în situaţia de a
elabora schema unei baze de date pentru o problemă/aplicaţie practică (deci, invitabil,
reală) au apărut elemente ce au pus la grea încercare fundamentul teoretic al normalizării.
Din experienţă şi cazuistica lucrului cu studenţii de la specializarea Informatică
Economică, vă prezint astăzi câteva asemenea cazuri care, în marea majoritate a lucrărilor
dedicate proiectării bazelor de date, sunt eludate sau sever simplificate pentru a evita
durerile de cap. Mă refer chiar la autori celebri, precum Date, Teorey, Riordan, Connolly,
Begg şi Strachan, Flemming şi von Halle sau Celko.
Acum doi ani (PCReport nr. 92/mai 2000), v-am prezentat un material despre prima
forma normală. Mă aşteptam la oarecare răceală atât din partea redacţiei, cât şi a
cititorilor, dat fiind că subiectul părea a fi unul entry-level în proiectarea bazelor de date,
în vădită contradicţie cu nivelul cititorilor revistei. N-aş zice că entuziasmul provocat de
articol a fost unul deşănţat, dar am avut suficiente motive pentru a prinde ceva curaj şi
iată-mă-s prezentându-vă câteva găselniţe ale 2NF şi 3NF. Cât despre forma normalizată
Boyce-Codd sau 4NF şi 5NF, aici lucrurile sunt şi mai pestriţe, după cum probabil vom
vedea într-un material viitor (care, dacă ar fi să respect ritmul, l-aş trimite redacţiei peste
exact un an).
Până la un punct, reţeta este simplă şi chiar simpatică. Din păcate, realitatea este mai
complicată, uneori, pur şi simplu, refuzând să se supună teoriei ! În cele ce urmează ne
vom ocupă doar de primele etape din cele prezentate mai sus.
Dependenţe funcţionale
unde: R este numele relaţiei, iar Ai sunt atributele relaţiei R, şi prin X şi Y două
subansamble ale ansamblului {A1, A2,...., An}, se spune că există o dependenţă
funcţională între X şi Y dacă şi numai dacă :
- fiecare apariţie (valoare) a lui X poate fi asociată unei singure apariţii a lui Y,
- două apariţii identice ale lui X nu pot fi asociate decât aceleiaşi apariţii a lui Y.
Se notează X —→ Y.
Într-o prezentare şi mai explicită, Date defineşte dependenţa funcţională după cum
urmează: Dată fiind o relaţie R, subansamblul de atribute Y din R depinde funcţional de
subansamblul X (tot din R), dacă şi numai dacă, ori de câte ori două tupluri din R
prezintă aceeaşi valoare pentru X, obligatoriu valoarea celor două tupluri este identică
şi pentru Y.
Implicit, în orice relaţie R există dependenţele funcţionale: cheia lui R —→ celelalte
atribute ale lui R.
O dependenţă funcţională în care scopul (destinaţia) este alcătuit dintr-un singur atribut
se numeşte dependenţă funcţională canonică sau dependenţă funcţională în formă
canonică.
LOCALITĂŢI
Formal, dacă X = { Ai, Aj,...., Ak } reprezintă un grup de atribute ale relaţiei R, iar Am
un atribut al aceleiaşi relaţii, unde Am § X. Se spune că există o dependenţă funcţională
totală între X şi Am dacă:
1. X —→ Am ,
2. nu există nici un subansamblu S de atribute, S § X, pentru care S —→ Am .
Dependenţa funcţională totală mai este denumită şi elementară, plină, deplină sau
completă, prin opoziţie cu depedenţele parţiale, sau incompete.
Jan Heath a demonstrat că orice relaţie alcătuită din trei atribute, notat( R(X, Y, Z), în
care există dependenţa funcţională X —→ Y poate fi descompusă în două relaţii R1(X,
Y) şi R2(X, Z) [Heath71]; R1 şi R2 reprezentă proiecţiile relaţiile R pe atributele X şi Y,
respectiv X şi Z. Esenţial este faptul că descompunerea să se facă fără pierdere de
informaţii, adică R să poată fi "recompusă" prin joncţiunea tabelelor R1 şi R2. Astfel, se
poate rezolva problema cheii primare a relaţiei universale, în cazurile încălcării restricţiei
de entitate (un atribut din cheia primară prezintă valori nule).
1. Se află în 1NF.
Problema trecerii unei relaţii din prima în a doua formă normală se pune numai când
cheia primară a relaţiei este compusă din mai multe atribute. Într-o formulare mai lejeră,
se poate spune că o relaţie în 2FN nu conţine DF parţiale între atributele-cheie şi
celelalte atribute.
b) Se trec în revistă toate dependenţele care au ca sursă (determinant) un atribut sau sub-
ansamblu de atribute din cheia primară.
c) Pentru fiecare atribut (sau sub-ansamblu) al cheii de la pasul b), se creează o relaţie
care va avea drept identificator primar atributul (subansamblul) respectiv, iar celelalte
atribute vor fi cele care apar ca destinaţii în dependenţele de la pasul b).
Cheia primă a relaţiei LOCALITĂŢI din figura 1 prezintă problema nulităţii unuia dintre
atributele componente, deoarece singura combinaţie plauzibilă - (CodPoştal, Sat) -
încalcă restricţia de entitate (pentru liniile care se referă la oraşe valoarea atributului Sat
este NULL) Cu toate acestea se poate scrie:
(1) (CodPoştal, Sat) —→ OraşComună
Dar:
şi
Pentru a verifica justeţea ruperii relaţii iniţiale în cele două noi tabele, ar trebui ca prin
joncţiunea ORASE_COMUNE cu SATE să obţinem LOCALITĂŢI. Şi, într-adevăr prin
fraza standard SQL-92:
Avantajele descompunerii în cele două relaţii sunt vizibile. Mai întâi, ambele sunt în 1NF
şi au cheie primară. În al doilea rând, se elimină redundenţele. În LOCALITĂŢI, dacă o
comună are şase sate, de şase ori apare şi codul poştal al comunei, şi denumirea comunei
şi a judeţului. Acum însă, denumirea comunei şi judeţului apare o singură dată în relaţia
ORAŞE_COMUNE. De asemenea, pentru fiecare oraş apare o singură înregistrare în
ORAŞE_COMUNE şi, firesc, nici una în SATE.
Dacă avem în vedere teorema lui Heath, ruperea unei relaţii în mai multe tabele poate fi
făcută cu oarecare frenezie. Astfel, în LOCALITATI, pe baza DF: CodPoştal —→
OraşComună şi CodPoştal —→ Judeţ, baza de date poate fi adusă în 2FN şi astfel:
şi
Este clar că avem de-a face cu o exagerare, deşi toate cele trei relaţii respectă cu sfinţenie
condiţiile formei a doua normale. De cele mai multe ori, în normalizare se aplică
principiul obţinerii celui mai mic număr de relaţii care să răspecte condiţiile uneia sau
alteia dintre formele normalizate.
O dependenţă funcţională Dată1 —→ Dată2 este directă atunci când nu există o Dată3
care angajează o dependenţă funcţională tranzitivă de genul: Dată1 —→ Dată3 —→
Dată2.
Prima definiţie a celei de-a treia forme normale a unei relaţii poate fi formulată relativ
simplu şi incremental, prin raportare la 2NF. O relaţie se află în 3NF dacă:
1. Se găseşte în 2NF.
2. Toate atributele care nu aparţin cheii primare nu depind funcţional de un alt atribut
(ansamblu de atribute) care nu face parte din cheie.
Trecerea din 2NF în 3NF presupune eliminarea DF tranzitive şi se poate face, pentru o
relaţie, în următoarea manieră:
a) Se identifică toate atributele ce nu fac parte din cheie şi care sunt surse ale unor
dependenţe funcţionale.
b) Pentru toate atributele identificate la punctul a), se constituie câte o relaţie în care
cheie primară va fi atributul respectiv, iar celelate atribute destinaţiile din dependenţele
considerate.
Operaţiile a) şi b) se repetă şi pentru relaţiile "proaspăt" obţinute prin decompoziţie.
Chiar pentru cazuri simple, ansamblul tuturor DF într-o bază de date poate să devină
extrem de stufos. De aceea, în procesul normalizării trebuie avut în vedere un echilibru
între:
includerea în setul DF numai a celor relevante, din care, adică a unui ansamblu minimal
din care, prin reguli de genul celor de mai sus, se pot obţine toate celelalte DF.
Deseori, o bază de date sau relaţie prezintă mai multe chei candidat. Alegerea dintre
acestea a cheii primare are în vedere, pe lângă unicitate, compoziţie minimală şi valori
nenule ale oricărui atribut component, şi elemente ce ţin de facilitatea utilizării: uşurinţa
reţinerii (de către utilizator), lungime cât mai mică, constanţă în timp etc.
Spre exemplu, luăm în discuţie următoarea relaţie ce conţine informaţii despre firmele
client: R {CodClient, DenClient, Adresa, CodPoştal, Localitate, Judet, CodFiscal}.
Relaţia are trei chei candidate: CodClient, DenClient şi CodFiscal. La modul riguros, ar
trebuie scris:
Toate cele 18 dependenţe funcţionale sunt corecte şi totale. Perechile (1) şi (7), (6) şi
(13), (12) şi (14) sunt însă simetrice. Pe de altă parte, datorită dependenţei (8), ar însemna
că (2) este tranzitivă: CodClient —→ DenClient —→ Adresa, ceea ce e o exagerare.
Deşi nu elimină toate necazurile, pentru simplificare se recomandă alegerea unuia dintre
cele trei atribute drept cheie primară şi eliminarea tuturor depedenţelor funcţionale de
decurg din calitatea de cheie candidată a celorlalte atribute. Astfel, dacă am "unge" drept
cheie primară atributul CodClient, atunci dintre cele 18 dependenţe am păstra numai
primele şase, la care se adaugă cele în care sursa este CodPoştal.
După cum vom vedea în alt material, atunci când cheile candidate sunt compuse, discuţia
se complică şi mai mult, iar forma "clasică" a 3FN prezintă o serie de inadvertenţe.
Dealtminteri, aşa a "apărut" BCNF (Boyce-Codd Normal Form).
Să luăm un exemplu foarte simplu: R{Profesor, Birou, Catedră, Telefon} care conţine
date despre "domiciliul" în facultate al fiecărui profesor.
Un profesor are un singur birou (Birou identifică fără ambiguitate sala respectivă):
(1) Profesor —→ Birou
Într-un birou pot "locui" mai mulţi profesori (deşi, uneori, lucrul acesta îi nemulţumeşte
profund):
Fiecare birou este arondat unei singure catedre (Economie politică, Contabilitate etc.):
Din (3) ar reieşi că (2) este DF tranzitivă, iar relaţia ar trebui descompusă numai în:
R2 {Profesor, Birou}
Apare însă o situaţie ce aruncă în aer algoritmul nostru: un profesor are un birou alocat
altei catedre ! Situaţia este reală. Catedrele pot opera, temporar sau definitiv, schimburi
de birouri. Pentru profesorii care ocupă un birou alocat altei catedre, schema bazei
alcătuită din R1 şi R2 furnizează eronat răspunsul la întrebarea: Din ce catedră face parte
fiecare profesor ?
Dacă una din cele două afirmaţii de mai sus este adevărată, atunci dependenţa funcţională
A —→ E nu este directă.
Primul caz
În virtutea ultimelor trei dependenţe funcţionale, rezultă că dependenţele (3), (4) şi (5)
sunt tranzitive.
Al doilea caz
Pentru un plus de credibilitate, să luăm cazul unei baze de date pentru evidenţierea
rezultatelor studenţilor din sesiunile de pe parcursul unui universitar:
R {Matricol, NumePren, An, Modul, Spec, Grupa, CodDisc, DenDisc, NrCredDisc,
CodProf, NumeProf, GradProf, DataEx, SalaEx, Nota}
Relaţia R este în prima formă normalizată. Pentru a demonstra că nu este în 2FN trebuie
să găsim în ansamblul DF (1)- (12) măcar o DF parţială. Lucru destul de simplu, dacă
ţinem seamă de următoarele DF în care sursa o constituie unul dintre atributele
componente ale cheii.
(14) Matricol —→ An
CodDisc identifică în mod unic fiecare discplină din planul de învăţământ al specializării:
(18) CodDisc —→ DenDisc
Pe baza DF (20) şi (21), putem spune că (9) şi (10) sunt tranzitive, aşa încât rupem R3 în
R31 {CodProf, NumeProf, GradProf } şi R32 {Matricol, CodDisc, CodProf, DataEx,
SalaEx, Nota}.
Astfel, în 3NF, relaţia universală R are o schemă alcătuită din patru relaţii, după cum
urmează:
Nici una din cele patru relaţii nu conţine DF tranzitive. Cu toate acestea, schema este
departe de a fi optimă. Faţă de DF discutate, mai există două restricţii neluate în calcul în
normalizare:
La o serie de curs (seriile de curs se constituie, pentru fiecare disciplină, la nivel de an,
modul, specializare) titular este un singur profesor:
(22) (CodDisc, An, Modul, Spec) —→ CodProf
Studenţii unei specializări susţin examenul la o disciplină în aceeaşi sală (şi acceaşi zi):
dar şi
rezultă ca (8) este o DF necanonică, aşa încât relaţia NOTE1 s-ar descompune în:
şi
dar şi DF:
şi
Ajungem, astfel la o cu totul altă structură a bazei de date, mult mai bună decât
precedenta:
Într-un graf al dependenţelor funcţionale, acestea sunt reprezentate prin săgeţi ce leagă
sursa şi destinaţia. La dependenţele funcţionale simple săgeata uneşte cele două atribute.
Când sursa este compusă, se foloseşte un conector care leagă, în prima instanţă,
atributele-determinant, iar săgeata uneşte acest conector cu atributul destinaţie.
Astfel, pentru baze de date COMENZI, graful DF este reprezentat în figura 5, iar pentru
baza de date EXAMENE în figura 6.
Figura 5. DF tranzitive necanonice
Pe baza grafului DF, schema bazei de date poate fi adusă relaţiile direct în 3FN
constituindu-se câte o relaţie pentru fiecare sursă de DF, celelalte atribute fiind toate
destinaţiile respectivei surse. Fireşte atributul sau atributele sursă vor fi cheile primare ale
fiecăreia dintre tabele. Din figura 6 pot fi construite direct relaţiile din finalul paragrafului
precedent.
La tabelele obţinute în acest mod, este necesară uneori adăugarea unei relaţii care conţine
numai cheia primară compusă a relaţiei universale R, aceasta cu precădere în situaţiile în
care cheia primară a relaţiei universale nu apare ca sursă în graf şi, în plus, cheia primară
nu prezintă problema nulităţii vreunuia dintre atributele componente.
Mai trebuie spus că pentru 4FN şi 5FN graful nu prezintă prea mare importanţă, câtă
vreme depedenţele multivaloare şi de joncţiune nu sunt reprezentate, iar pentru BCFN
utilitatea este limitată.
Bibliografie