I tre livelli di astrazione
Progettare un database è un processo a tappe. Non si parte mai dal codice SQL: si inizia da una descrizione ad alto livello del dominio e si scende gradualmente verso l’implementazione. I tre livelli sono:
| Livello | Nome | Strumento | Domanda |
|---|---|---|---|
| 1 — Concettuale | Modello ER | Diagramma Entità-Relazione | Cosa voglio rappresentare? |
| 2 — Logico | Modello Relazionale | Schema tabelle / notazione R(A1, A2…) | Come lo organizzo in tabelle? |
| 3 — Fisico | Modello Fisico | SQL DDL (CREATE TABLE…) | Con quale DBMS lo implemento? |
Il livello concettuale è indipendente da qualsiasi tecnologia: descrive il problema. Il livello logico è indipendente dal DBMS specifico: potremmo usare MySQL o PostgreSQL e lo schema rimarrebbe uguale. Il livello fisico invece dipende dal DBMS scelto (tipi di dato, engine, partitioning). Separare i livelli permette di cambiare tecnologia senza riprogettare tutto.
Le regole di derivazione
La traduzione dal modello concettuale al logico segue regole precise e meccaniche. Imparandole, sai tradurre qualsiasi diagramma ER in uno schema relazionale corretto.
Regola 1 — Ogni entità diventa una tabella
Ogni entità ER diventa una tabella. Gli attributi dell’entità diventano colonne. L’identificatore dell’entità diventa la chiave primaria (PK).
→ STUDENTE(matricola, nome, cognome, data_nascita)
Regola 2 — Relazione 1:N → FK nella tabella lato N
La chiave primaria della tabella sul lato 1 viene aggiunta come chiave esterna alla tabella sul lato N.
→ DIPARTIMENTO(id_dip, nome, sede)
→ DIPENDENTE(id_dip_emp, nome, stipendio, FK:id_dip)
Regola 3 — Relazione 1:1 → FK in una delle due tabelle
Si mette la FK nella tabella “dipendente” o in quella che rende più senso semanticamente. Spesso è la tabella che non può esistere senza l’altra.
→ PERSONA(id_pers, nome, cognome)
→ PASSAPORTO(num_pass, data_rilascio, scadenza, FK:id_pers)
Regola 4 — Relazione N:M → tabella di giunzione
Si crea una nuova tabella con le FK di entrambe le entità. La PK della tabella di giunzione è solitamente la coppia delle due FK (chiave composta). Gli attributi di relazione finiscono qui.
→ STUDENTE(matricola, nome, cognome)
→ CORSO(id_corso, nome, crediti)
→ FREQUENTA(FK:matricola, FK:id_corso, voto_finale)
Regola 5 — Attributi multivalore → tabella separata
Se un’entità ha un attributo che può avere più valori (es. una persona con più numeri di telefono), non si possono mettere nella stessa riga. Si crea una tabella separata.
→ PERSONA(id_pers, nome, cognome)
→ TELEFONO(id_tel, numero, tipo, FK:id_pers)
Caso studio completo: LIBRO e AUTORE
Vediamo l’applicazione di tutte le regole su un caso realistico. Una biblioteca digitale ha libri scritti da uno o più autori, e ogni autore può aver scritto più libri.
EDITORE è sul lato 1 della relazione con LIBRO → la FK va in LIBRO. Il campo id_editore in LIBRO punta alla PK di EDITORE. La relazione N:M LIBRO–AUTORE genera la tabella di giunzione LIBRO_AUTORE. L’attributo ruolo descrive la relazione (coautore, curatore, traduttore) e non potrebbe stare né in LIBRO né in AUTORE.
Integrità referenziale
Il DBMS applica questo vincolo automaticamente se dichiarato. Tre situazioni possono violare l’integrità referenziale, e per ognuna esistono comportamenti configurabili:
Caso 1 — INSERT su tabella figlia
Si prova ad inserire un ORDINE con id_cli = 999 ma il cliente 999 non esiste. → Il DBMS restituisce errore e l’INSERT viene rifiutato. Non c’è alcuna opzione di comportamento: è sempre un errore.
Caso 2 — UPDATE della PK padre
Si vuole aggiornare la PK di un CLIENTE che ha già ordini. Cosa succede agli ordini che puntano alla vecchia PK?
| Comportamento | Cosa fa | Quando usarlo |
|---|---|---|
CASCADE | Aggiorna automaticamente tutte le FK figlie | PK naturale che può cambiare (es. codice fiscale) |
RESTRICT / NO ACTION | Blocca l’UPDATE se esistono figli | PK artificiale (auto-increment) — non dovrebbe mai cambiare |
SET NULL | Imposta la FK figlia a NULL | Relazione opzionale, figlio può esistere senza padre |
Caso 3 — DELETE del record padre
Si vuole eliminare un CLIENTE. Cosa succede ai suoi ordini?
| Comportamento | Cosa fa | Esempio d’uso |
|---|---|---|
CASCADE | Elimina in cascata tutti i figli | Elimina un post → elimina tutti i commenti |
RESTRICT | Blocca il DELETE se esistono figli | Non puoi eliminare un cliente con ordini in corso |
SET NULL | Imposta la FK figlia a NULL | Elimina un autore → i libri rimangono senza autore assegnato |
SET DEFAULT | Imposta la FK al valore di default | Meno comune, usato per riassegnare a un record “generico” |
ON DELETE CASCADE è potente ma pericoloso: elimina in modo silenzioso migliaia di record figli. Usalo solo dove la logica applicativa lo richiede esplicitamente (es. relazioni di proprietà: elimina utente → elimina tutti i suoi dati). Evitalo dove i dati figli hanno valore indipendente (es. ordini storici, dati contabili).
Schema finale con vincoli dichiarati
Una buona pratica è annotare esplicitamente i comportamenti FK già nel livello logico, prima di scrivere il DDL:
Se eliminiamo un libro, ha senso che scompaiano le associazioni autore-libro (CASCADE). Se eliminiamo un autore, non possiamo farlo se esistono libri a lui collegati, per non creare orfani (RESTRICT).
- Tre livelli: Concettuale (ER) → Logico (tabelle) → Fisico (SQL DDL). Si progetta sempre dall’alto verso il basso.
- Regole di derivazione: entità → tabella; 1:N → FK nel lato N; 1:1 → FK in una tabella; N:M → tabella di giunzione; multivalore → tabella separata.
- Integrità referenziale: ogni FK deve puntare a una PK esistente. I DBMS la garantiscono se dichiarata.
- Su UPDATE/DELETE del padre:
CASCADEpropaga,RESTRICTblocca,SET NULLazzera la FK. ON DELETE CASCADEè potente ma va usato con consapevolezza: elimina silenziosamente tutti i figli.