Pe scurt
Normalizarea organizează tabelele pentru a reduce repetarea inutilă și anomaliile la actualizare. Dacă fiecare elev păstrează și numele clasei „9A” în propriul rând, schimbarea denumirii clasei cere modificarea tuturor elevilor. Separând Clase(id, denumire) de Elevi(id, nume, clasa_id), numele clasei se schimbă într-un singur loc.
În detaliu
Normalizarea organizează tabelele pentru a reduce repetarea inutilă a datelor și anomaliile la actualizare, inserare și ștergere. Primul pas este identificarea entităților diferite: datele elevului și datele clasei descriu entități diferite și se păstrează în tabele separate, legate printr-o cheie externă. Normalizarea nu înseamnă un tabel separat pentru fiecare coloană; structura urmărește dependențele dintre atribute și întrebările aplicației.
Primele trei forme normale oferă verificări progresive. Forma normală 1 (1FN): fiecare celulă păstrează o valoare atomică, nu o listă de note într-o singură celulă. Forma normală 2 (2FN): un atribut necheie dintr-un tabel cu cheie compusă depinde de întreaga cheie; într-o înscriere identificată prin (elev_id, curs_id), numele elevului depinde doar de elev_id și aparține tabelului elevilor. Forma normală 3 (3FN): un atribut necheie nu depinde tranzitiv de cheie prin alt atribut necheie; dacă clasa_id determină dirigintele, dirigintele se păstrează în tabelul claselor, nu lângă fiecare elev.
Exemplul 1 — anomalia de actualizare. Într-un singur tabel, clasa și dirigintele ei se repetă în rândul fiecărui elev. Dirigintele clasei 9A este schimbat doar în rândul Anei:
CREATE TABLE elevi_nenorm (id integer PRIMARY KEY, nume text, clasa text, diriginte text);
INSERT INTO elevi_nenorm VALUES (1, 'Ana', '9A', 'Ionescu'),
(2, 'Dan', '9A', 'Ionescu'),
(3, 'Mara', '9B', 'Popa');
UPDATE elevi_nenorm SET diriginte = 'Marin' WHERE id = 1;
SELECT DISTINCT clasa, diriginte FROM elevi_nenorm ORDER BY clasa, diriginte;
Interogarea întoarce trei rânduri: (9A, Ionescu), (9A, Marin) și (9B, Popa). Aceeași clasă are acum doi diriginți, deci datele sunt contradictorii: actualizarea parțială a lăsat denumiri diferite pentru același fapt. Dependența clasa → diriginte este tranzitivă față de cheia id, deci tabelul nu este în 3FN.
Exemplul 2 — structura normalizată. Faptele despre clasă se mută în clase, iar elevi păstrează doar cheia externă. Schimbarea dirigintelui se face într-un singur loc, iar legătura elev–clasă se păstrează prin cheia externă:
CREATE TABLE clase (id integer PRIMARY KEY, denumire text NOT NULL,
diriginte text NOT NULL);
CREATE TABLE elevi (id integer PRIMARY KEY, nume text NOT NULL,
clasa_id integer NOT NULL REFERENCES clase(id));
INSERT INTO clase VALUES (9, '9A', 'Ionescu'), (10, '9B', 'Popa');
INSERT INTO elevi VALUES (1, 'Ana', 9), (2, 'Dan', 9), (3, 'Mara', 10);
UPDATE clase SET diriginte = 'Marin' WHERE id = 9;
SELECT elevi.nume, clase.denumire, clase.diriginte
FROM elevi JOIN clase ON elevi.clasa_id = clase.id ORDER BY elevi.id;
Rezultatul este (Ana, 9A, Marin), (Dan, 9A, Marin), (Mara, 9B, Popa): o singură comandă a schimbat dirigintele pentru toți elevii clasei 9A. Pentru prima formă normală, notele lui Ana nu se păstrează ca text 8,9,10 într-o celulă, ci ca rânduri (1,8), (1,9), (1,10) într-un tabel note(elev_id, nota); media se calculează atunci cu AVG(nota) și este .
Exemplul 3 — cheia compusă și forma normală 2. Tabelul inscrieri_nenorm are cheia (elev_id, curs_id), dar numele elevului depinde numai de elev_id, deci nu respectă 2FN.
CREATE TABLE inscrieri_nenorm (elev_id integer, curs_id integer, nume_elev text, nota integer,
PRIMARY KEY (elev_id, curs_id));
INSERT INTO inscrieri_nenorm VALUES (1, 10, 'Ana', 9), (1, 11, 'Ana', 8), (2, 10, 'Dan', 7);
DELETE FROM inscrieri_nenorm WHERE elev_id = 2 AND curs_id = 10;
SELECT COUNT(*) FROM inscrieri_nenorm WHERE elev_id = 2;
Numele „Ana” este scris de două ori, deci o corectură a numelui cere două modificări. Ștergerea singurei înscrieri a lui Dan lasă interogarea cu rezultatul 0: odată cu înscrierea s-a pierdut și faptul că există un elev numit Dan (anomalie de ștergere). Pentru același motiv, un elev încă neînscris la niciun curs nu are unde să fie memorat, fiindcă cheia cere ambele valori. Soluția este separarea: elevi(id, nume) păstrează numele o singură dată, iar inscrieri(elev_id, curs_id, nota) păstrează doar ce depinde de întreaga cheie. După aceeași ștergere, elevul Dan rămâne în elevi.
Prima formă normală cere valori atomice și pentru adrese, dacă aplicația le folosește separat: dacă se caută elevii dintr-un oraș, orașul trebuie păstrat într-o coloană proprie, nu în mijlocul textului 'Str. Florilor 5, Cluj'.
Greșeli frecvente
- Greșit: normalizarea înseamnă un tabel separat pentru fiecare valoare.Corect: separă faptele după relațiile dintre atribute.
- Greșit: repetarea numelui clasei în fiecare rând nu poate cauza inconsistențe.Corect: actualizările parțiale pot lăsa denumiri diferite.
- Greșit: după separare se pierde legătura elev–clasă.Corect: se păstrează prin cheia externă.
Testează-te pe această lecție
Lecția o citești aici, fără cont. Testele pe lecții și capitole sunt în cont, cu grile originale Didaxis și explicația fiecăreia: gratuit 10 grile pe zi, fără limită cu Premium, 49 de lei pe lună pentru fiecare copil.
Înainte și după
Surse și referințe
Redactare proprie, conform programei:
- OMECI 5099/2009, anexa 5, Informatică, p. 3–4, 7, clasa XII; rocnee.eu
- OMECI 5099/2009, anexa 5, Informatică, p. 3, 7, clasa XII; plan de încadrare: OMEC 7723/2024, anexa 2, tabelele 1–25, legislatie.just.ro; filiera tehnologică: OMEC 7724/2024, anexa 4, tabelul calificării, legislatie.just.ro
Documente consultate
- Programa școlară de informatică, clasa a XII-a (OMECI 5099/2009, anexa 5), CNCE, modulul Baze de date, p. 3 și 7; rocnee.eu
- OpenStax, Introduction to Computer Science, cap. 8.3 „Relational Database Management Systems”, openstax.org/books/introduction-computer-science/pages/8-3-relational-database-management-systems
Desene: Redactare proprie (desen original)
