La normalizzazione è il procedimento con cui si organizza un database relazionale in modo che ogni informazione sia memorizzata una sola volta e nel posto giusto. Il termine suona accademico, ma l'obiettivo è molto pratico: evitare che inserimenti, modifiche e cancellazioni producano dati contraddittori. Il modo migliore per capirla è partire da una tabella fatta male e sistemarla un passo alla volta.
La tabella di partenza
Immaginiamo un piccolo negozio online che registra tutto in un'unica tabella:
| ordine | data | cliente | email_cliente | città_cliente | prodotti |
|---|---|---|---|---|---|
| 101 | 2025-03-02 | Rossi | rossi@esempio.it | Torino | Penna x2, Quaderno x1 |
| 102 | 2025-03-02 | Bianchi | bianchi@esempio.it | Bari | Quaderno x3 |
| 103 | 2025-03-05 | Rossi | rossi@esempio.it | Torino | Zaino x1 |
Funziona finché i dati sono pochi, ma nasconde tre tipi di problemi, chiamati anomalie.
- Anomalia di aggiornamento: se Rossi cambia email, va modificata su ogni suo ordine. Dimenticarne uno crea un'incoerenza.
- Anomalia di inserimento: non si può registrare un nuovo cliente finché non ha fatto un ordine, perché ogni riga è un ordine.
- Anomalia di cancellazione: se si elimina l'unico ordine di Bianchi, si perde anche l'informazione che Bianchi esiste e abita a Bari.
Prima forma normale (1NF)
Una tabella è in prima forma normale quando ogni cella contiene un valore atomico, cioè uno solo, e non ci sono gruppi ripetuti. La colonna «prodotti» viola questa regola: contiene un elenco, per giunta con le quantità mescolate al nome.
Per sistemarla si crea una riga per ogni prodotto ordinato:
| ordine | data | cliente | email_cliente | città_cliente | prodotto | quantità |
|---|---|---|---|---|---|---|
| 101 | 2025-03-02 | Rossi | rossi@esempio.it | Torino | Penna | 2 |
| 101 | 2025-03-02 | Rossi | rossi@esempio.it | Torino | Quaderno | 1 |
Ora si può contare quante penne sono state vendute con una semplice query, cosa impossibile quando i prodotti erano testo libero. La chiave della tabella diventa la coppia (ordine, prodotto).
Seconda forma normale (2NF)
La seconda forma normale riguarda le tabelle con chiave composta. Richiede che ogni colonna non chiave dipenda dall'intera chiave, non da una sua parte.
Nella tabella precedente la quantità dipende da ordine e prodotto insieme: va bene. Ma data, cliente, email e città dipendono solo dal numero d'ordine. Sono ripetute per ogni riga di prodotto senza motivo.
La soluzione è separare:
- ordini (ordine, data, cliente, email_cliente, città_cliente)
- righe_ordine (ordine, prodotto, quantità)
Allo stesso modo, se avessimo il prezzo di listino del prodotto nella tabella delle righe, andrebbe spostato in una tabella prodotti, perché dipende solo dal prodotto.
Terza forma normale (3NF)
La terza forma normale elimina le dipendenze transitive: una colonna non chiave non deve dipendere da un'altra colonna non chiave. Nella tabella ordini, email e città non dipendono dall'ordine in sé, ma dal cliente. L'ordine determina il cliente, e il cliente determina email e città.
Si crea quindi una tabella clienti e la tabella ordini conserva solo un riferimento:
CREATE TABLE clienti (
id_cliente INTEGER PRIMARY KEY,
nome TEXT NOT NULL,
email TEXT NOT NULL UNIQUE,
citta TEXT
);
CREATE TABLE ordini (
id_ordine INTEGER PRIMARY KEY,
data_ordine DATE NOT NULL,
id_cliente INTEGER NOT NULL REFERENCES clienti(id_cliente)
);
CREATE TABLE righe_ordine (
id_ordine INTEGER REFERENCES ordini(id_ordine),
id_prodotto INTEGER REFERENCES prodotti(id_prodotto),
quantita INTEGER NOT NULL CHECK (quantita > 0),
PRIMARY KEY (id_ordine, id_prodotto)
);
Le tre anomalie sono sparite: l'email si cambia in un solo punto, un cliente può esistere senza ordini e cancellare un ordine non cancella il cliente.
Un modo semplice per ricordarle
Una formula spesso usata per riassumere le tre forme è che ogni attributo deve dipendere «dalla chiave, da tutta la chiave e da nient'altro che la chiave». La prima parte corrisponde alla 1NF, la seconda alla 2NF, la terza alla 3NF. Esistono forme normali successive, come la forma normale di Boyce-Codd, ma nella pratica quotidiana arrivare alla terza risolve la grande maggioranza dei problemi.
Quando denormalizzare
Normalizzare non significa frammentare tutto all'infinito. Ci sono casi in cui duplicare un dato è una scelta corretta:
- Dati storici. Il prezzo pagato va salvato nella riga d'ordine anche se esiste nella tabella prodotti, perché il listino cambierà e l'ordine deve ricordare il prezzo di quel giorno. Non è una ridondanza: è un'informazione diversa.
- Indirizzo di spedizione. Allo stesso modo, l'indirizzo usato per un ordine va congelato nell'ordine.
- Report e analisi. Nei sistemi dedicati all'analisi si usano spesso tabelle volutamente denormalizzate per rendere le query più semplici e veloci.
La regola pratica è partire da un modello normalizzato e denormalizzare solo per un motivo preciso, documentandolo.
In sintesi
- La normalizzazione elimina le anomalie di aggiornamento, inserimento e cancellazione.
- 1NF: valori atomici, niente elenchi dentro una cella.
- 2NF: nessuna colonna dipende solo da una parte della chiave composta.
- 3NF: nessuna colonna dipende da un'altra colonna non chiave.
- Si denormalizza solo per ragioni chiare, come conservare dati storici.