Finiamo di analizzare la fase di progettazione del database trattando altri
due argomenti importanti: la normalizzazione del database e le
regole d’integrità.
Le regole di normalizzazione
Abbiamo detto nella prima lezione che ogni tabella deve contenere
un certo tipo di cose (o entità) che rappresentano un oggetto
o un evento del mondo reale. Ma quando si progetta un database
come si fa a vedere quante tabelle servono o quali colonne dovranno
avere?
Le regole di normalizzazione ci aiutano in fase di progettazione
a trovare la struttura ottimale per il nostro database. Si tratta
di una serie di criteri che ci guidano nella costruzione delle
singole tabelle in modo tale da realizzare un database che sia
il più efficiente possibile. Si parla di vari livelli di normalizzazione,
uno successivo all’altro; cioè un database per soddisfare
il secondo livello di normalizzazione deve necessariamente soddisfare
il primo livello e così via per quelli successivi. Noi prenderemo
in esame solamente i primi tre livelli, in quanto un database
che soddisfi il terzo livello di normalizzazione già raggiunge
un elevato grado di efficienza e ci sono buone probabilità che
soddisfi anche alcuni livelli successivi.
Primo livello di normalizzazione
Il primo livello di normalizzazione (1NF, first normal form) richiede
che tutti i valori di ogni colonna siano indivisibili. Esempio
classico: mettere in un unico campo nome e cognome di un soggetto
non soddisfa il primo livello di normalizzazione in quanto il
valore può essere suddiviso in nome e cognome. Il motivo che sta
alla base di questa regola è facilmente intuibile: se una colonna
contiene più valori non è possibile riutilizzarli in maniera semplice
ed immediata. Nel caso di nome e cognome il problema è limitato,
ma si pensi ad un database che gestisce gli ordini di un commerciante
all’ingrosso di frutta: se gli acquisti di ogni cliente
vengono inseriti tutti in una colonna (es. il cliente Bianchi
compra 10 kg,. di banane, 20 kg di mele, e così via per altri
10 tipi di frutta) il problema dell’estrazione e dello sfruttamento
dei dati diventa notevole. Quindi i dati devono essere suddivisi
in più colonne in modo tale che ogni colonna contenga solamente
una singola informazione.
Però bisogna stare attenti a come si traduce in pratica questa
regola infatti se nella stessa tabella ordini facessimo tante
colonne quanti sono i possibili prodotti che possono essere acquistati
commetteremmo un altro errore. Infatti prima di tutto dovremmo
prestabilire un numero massimo di tipi di frutta che ogni cliente
può ordinare. E se qualcuno fa un ordine più grande di quelli
previsti? E ancora, quante colonne vuote vengono sprecate per
chi ordina solamente pochi tipi di frutta? E’ evidente che
questa non è la maniera corretta per progettare il nostro database.
La corretta strutturazione per risolvere un problema di questo
tipo può essere quella di assegnare una riga (record) per ogni
ordine inserendo il dettaglio di ogni ordine (per esempio il tipo
di frutta ordinato) in un’altra tabella la quale è messa
in relazione con la prima. La seconda tabella a sua volta conterrà
in ogni riga il riferimento all’ordine principale e ogni
riga individuerà un solo prodotto acquistato.
Secondo livello di normalizzazione
Il secondo livello di normalizzazione si ha quando una tabella
soddisfa il primo livello di normalizzazione e contemporaneamente
ogni colonna è totalmente dipendente dall’intera chiave
primaria. La parola “intera” è molto importante in
quanto la chiave primaria può essere formata da più di un campo.
In questi casi va verificato se tutti i campi non chiave dipendono
dall’intera chiave primaria o ci sono alcuni di essi che
invece dipendono solo da uno dei campi che formano la chiave.
Se si verificasse quest’ultimo caso, per ricondurre la tabella
al secondo livello di normalizzazione, sarebbe necessario scomporla
in più tabelle relazionate tra loro.
Torniamo al nostro commerciante di frutta ipotizzando una tabella
così formata: chiave primaria composta da due campi il campo che
contiene il numero dell’ordine ed il campo che contiene
il prodotto acquistato;
num_ordine |
num_prodotto |
num_cliente |
data_ordine |
quantità |
1 |
5 |
25 |
02/01/2002 |
15 |
1 |
8 |
25 |
02/01/2002 |
25 |
1 |
9 |
25 |
02/01/2002 |
14 |
2 |
6 |
13 |
03/01/2002 |
10 |
2 |
7 |
13 |
03/01/2002 |
12 |
3 |
5 |
11 |
04/02/2002 |
25 |
Questa tabella è 1NF perché ogni campo contiene valori indivisibili;
anche il problema dell’acquisto di più prodotti da parte
di uno stesso cliente è stato risolto con lo stratagemma di unire
il numero dell’ordine con il codice del prodotto, assegnando
una riga per ogni coppia ordine prodotto. Ma questa tabella non
2NF. Infatti è evidente come i campi num_cliente e data_ordine
non dipendono dall’intera chiave primaria, ma solo dal campo
num_ordine. In altre parole potremmo anche dire che ci sono dei
valori (la data ed il cliente) che si ripetono per ogni riga dell’ordine
ed il cui inserimento multiplo non serve a niente se non a occupare
spazio. Ancora una volta la soluzione può essere quella proposta
in precedenza cioè scomponendo la tabella in due tabelle: la prima
che contenga gli elementi essenziali dell’ordine e quindi
il numero la data ed il cliente; la seconda che contenga il dettaglio
dell’ordine e quindi, ad esempio, i prodotti acquistati
e le quantità. Le due tabelle saranno poi messe in relazione tra
loro attraverso il campo numero ordine.
Terzo livello di normalizzazione
Il terzo livello di normalizzazione si ha quando una tabella
soddisfa il secondo livello di normalizzazione e contemporaneamente
tutti i campi diversi dalla chiave primaria sono indipendenti
l’uno dall’altro. Un esempio di dipendenza è una colonna
calcolata (esempio classico nel caso di vendita la quantià per
il prezzo). Tuttavia una tabella con il campo ricavo totale calcolato
come moltiplicazione del campo prezzo per il campo quantità non
è normalizzata al terzo livello. E’ molto più efficiente
se questo calcolo viene fatto fare ad una query, o viene eseguito
in fase di stampa. Così facendo si occupa meno spazio nel database
e si evita di dover ricalcolare il valore quando viene modificato
uno degli altri valori.
I campi dipendenti (che non si hanno solo nel caso di calcoli)
creano problemi quando si decide di modificare, aggiornare o cancellare
dei record. Ipotizziamo una tabella composta dal campo ordine,
codice prodotto e descrizione prodotto; il campo descrizione prodotto
è dipendente dal campo codice prodotto. Ipotizziamo che ci siano
1000 ordini per il prodotto uva; dopo aver inserito questi ordini
si decide di modificare la descrizione dell’articolo uva
per distinguere quelle provenienti dal vigneto A da quelle del
vigneto B. Dovremmo aggiornare tutti i 1000 record precedentemente
inseriti. Anche in questo caso è molto più efficiente scindere
la tabella in due tabelle messe in relazione tra loro: una che
conterrà il numero dell’ordine ed il codice del prodotto,
l’altra che conterrà il codice del prodotto e la relativa
descrizione.
Torna all'indice Generale del corso di Corso di Microsoft Access di Software Planet