Le forme normali

// obiettivi di apprendimento
Comprendere perché la normalizzazione esiste e quali anomalie elimina
Verificare se una tabella soddisfa la 1NF, la 2NF e la 3NF
Normalizzare una tabella violata fino alla 3NF decomposto in tabelle separate
Distinguere dipendenza funzionale, dipendenza parziale e dipendenza transitiva
🎬
Video
Normalizzazione 1NF → 2NF → 3NF passo per passo
Guarda →
📄
Slides
Checklist NF e casi d’esame con soluzioni
Scarica →
⚗️
Lab
Normalizzazione di schemi reali: ordini e anagrafica
GitHub →
🔗
Risorse
Articoli e tool per verificare la normalizzazione
Vedi →

Perché normalizzare

Un database mal progettato produce ridondanza — lo stesso dato memorizzato in più posti — e anomalie nelle operazioni di modifica. La normalizzazione è il processo che porta uno schema relazionale a una forma che elimina queste anomalie, decomponendo le tabelle in strutture più pulite e coerenti.

// le tre anomalie che la normalizzazione elimina
INSERT Non si può inserire un dato senza inserirne un altro che non si conosce ancora. Es.: non posso inserire un nuovo corso se non ho ancora studenti iscritti.
UPDATE Lo stesso dato è in più righe: se cambia, devo aggiornarlo in tutti i posti. Se dimentico una riga, il database diventa inconsistente.
DELETE Eliminando un record, si perdono per sbaglio informazioni su un’altra entità. Es.: elimino l’ultimo studente di un corso e perdo le informazioni sul corso stesso.

Dipendenza funzionale

// definizione formale
Si dice che l’attributo B dipende funzionalmente da A (A → B) se per ogni valore di A esiste un solo valore di B. Oppure: conoscere A è sufficiente per determinare B. La dipendenza funzionale è la base teorica su cui si costruiscono tutte le forme normali.

Esempi di dipendenze funzionali:

matricola → nome, cognome, data_nascita
codice_fiscale → nome, cognome, data_nascita, comune_nascita
id_ordine → data_ordine, totale, id_cliente
(id_ordine, id_prodotto) → quantità, prezzo_unitario ← dipendenza da PK composta

Prima Forma Normale (1NF)

// definizione 1NF
Una tabella è in Prima Forma Normale (1NF) se e solo se: tutti gli attributi contengono valori atomici (non divisibili, non liste), non esistono gruppi ripetuti di attributi e la tabella ha una chiave primaria definita.

Esempio di violazione 1NF

Una tabella ORDINE in cui il campo prodotti contiene una lista separata da virgole:

id_ordineclienteprodottiquantità
1001Mario RossiPenna, Quaderno, Matita2, 1, 3
1002Anna BianchiMonitor1
// violazione 1NF

Il campo prodotti non è atomico: contiene più valori. Non posso fare una query per “tutti gli ordini che contengono Quaderno” senza analizzare la stringa. Ogni cella deve contenere un solo valore.

Correzione → 1NF

Si spacca ogni prodotto in una riga separata. La PK diventa composta: (id_ordine, id_prodotto).

id_ordineclienteid_prodottonome_prodottoquantità
1001Mario RossiP01Penna2
1001Mario RossiP02Quaderno1
1001Mario RossiP03Matita3
1002Anna BianchiP04Monitor1

La tabella è ora in 1NF, ma introduce una nuova anomalia: il nome del cliente è ripetuto per ogni prodotto dello stesso ordine. Se Mario Rossi cambia nome (o è registrato con un errore), devo aggiornare più righe. Serve la 2NF.

Seconda Forma Normale (2NF)

// definizione 2NF
Una tabella è in Seconda Forma Normale (2NF) se è in 1NF e tutti gli attributi non-chiave dipendono dall’intera chiave primaria, non solo da una parte di essa. La 2NF è rilevante solo quando la PK è composta da più attributi.

Violazione 2NF: dipendenza parziale

Nella tabella precedente con PK composta (id_ordine, id_prodotto):

(id_ordine, id_prodotto) → quantità ✓ dipende dall’intera PK
id_ordine → cliente ✗ dipendenza PARZIALE (solo da metà PK)
id_prodotto → nome_prodotto ✗ dipendenza PARZIALE (solo da metà PK)

Correzione → 2NF

Si separano gli attributi con dipendenza parziale in tabelle proprie:

ORDINE(id_ordine, id_cliente, data)
CLIENTE(id_cliente, nome, cognome)
PRODOTTO(id_prodotto, nome_prodotto, prezzo)
DETTAGLIO_ORDINE(FK:id_ordine, FK:id_prodotto, quantità)

Ora ogni tabella contiene solo attributi che dipendono interamente dalla propria PK. Nessuna ridondanza del nome cliente per ogni prodotto.

Terza Forma Normale (3NF)

// definizione 3NF
Una tabella è in Terza Forma Normale (3NF) se è in 2NF e nessun attributo non-chiave dipende da un altro attributo non-chiave. In altre parole: non esistono dipendenze transitive tra attributi non-chiave.

Violazione 3NF: dipendenza transitiva

Considera la tabella CLIENTE con il campo città e il relativo codice postale:

id_clientenomecittàprovinciacap
1MarioMilanoMI20121
2AnnaRomaRM00100
3LucaMilanoMI20121
id_cliente → città ✓ dipende dalla PK
città → provincia, cap ✗ TRANSITIVA: non-chiave dipende da non-chiave
id_cliente → città → provincia, cap ✗ dipendenza TRANSITIVA
// anomalia update

Se il CAP di Milano cambia, devo aggiornarlo in ogni riga di ogni cliente milanese. Se ne dimentico uno, il database è inconsistente: due clienti milanesi con CAP diversi.

Correzione → 3NF

Si estrae la dipendenza transitiva in una tabella separata:

CLIENTE(id_cliente, nome, cognome, FK:id_città)
CITTÀ(id_città, nome, provincia, cap)

Ora provincia e CAP esistono una sola volta per ogni città. Aggiornare il CAP di Milano richiede una sola modifica in CITTÀ.

Il percorso di normalizzazione — visione d’insieme

TABELLA GREZZA (non normalizzata) │ elimina valori non atomici e gruppi ripetuti ▼ 1NF — attributi atomici + PK definita │ elimina dipendenze parziali (solo con PK composta) ▼ 2NF — tutti gli attributi dipendono dall’intera PK │ elimina dipendenze transitive (non-chiave → non-chiave) ▼ 3NF — nessuna dipendenza transitiva tra non-chiave │ elimina anomalie residue (BCNF, 4NF, 5NF) ▼ BCNF / 4NF / 5NF (avanzate — per corsi universitari)
// fino a dove normalizzare

Per le applicazioni scolastiche e la maggior parte dei sistemi aziendali, la 3NF è sufficiente. Le forme normali superiori (BCNF, 4NF, 5NF) affrontano casi più sottili e vengono studiate nei corsi universitari di basi di dati avanzati. Talvolta si sceglie deliberatamente di de-normalizzare per ragioni di performance (es. data warehouse): l’importante è farlo consapevolmente.

Esempio completo: gestione ordini dal caos alla 3NF

Partiamo da questa tabella piatta — come potrebbe essere un foglio Excel — e arriviamo a uno schema normalizzato in 3NF.

Tabella di partenza (non normalizzata)

id_orddatanome_clicittà_cliprovprodottiqtàprezzinome_venditorezona_venditore
10012024-01-10Mario RossiMilanoMIPenna, Quaderno2, 10.50, 2.00Giulia VerdiNord
10022024-01-11Anna BianchiRomaRMMonitor1250.00Marco NeriCentro

Schema finale normalizzato in 3NF

// 1NF: eliminati valori multipli in prodotti, qtà, prezzi
// 2NF: eliminate dipendenze parziali da PK composta
// 3NF: eliminate dipendenze transitive (prov da città, zona da venditore)

CITTÀ(id_città, nome, provincia)

VENDITORE(id_vend, nome, FK:id_zona)
ZONA_VENDITA(id_zona, nome) ← 3NF: zona non dipende da venditore, è un’entità

CLIENTE(id_cli, nome, cognome, FK:id_città)

PRODOTTO(id_prod, nome, prezzo_listino)

ORDINE(id_ord, data, FK:id_cli, FK:id_vend)

DETTAGLIO_ORDINE(FK:id_ord, FK:id_prod, quantità, prezzo_unitario)
// risultato della normalizzazione

Da 1 tabella con 10 colonne e anomalie evidenti siamo arrivati a 6 tabelle pulite. Ogni dato esiste in un solo posto. Il prezzo di un prodotto si aggiorna una sola volta. La provincia di una città è memorizzata una sola volta. Nessuna anomalia di inserimento, modifica o cancellazione.

📌 Riepilogo — Punti chiave
  • La normalizzazione elimina ridondanze e le tre anomalie: di inserimento, di modifica e di cancellazione.
  • 1NF: attributi atomici, nessun gruppo ripetuto, PK definita.
  • 2NF: in 1NF + no dipendenze parziali (tutti i non-chiave dipendono dall’intera PK). Si applica solo se la PK è composta.
  • 3NF: in 2NF + no dipendenze transitive (nessun non-chiave dipende da un altro non-chiave).
  • La dipendenza funzionale (A → B) è la base teorica: B è univocamente determinato da A.
  • Per la maggior parte dei sistemi reali, la 3NF è il target. De-normalizzare consapevolmente per performance è accettabile, farlo per pigrizia no.

Lascia un commento