Vai al contenuto
eLearner.app
Modulo 9 · Lezione 2 di 434/57 nel corso~12 min
Lezioni del modulo (2/4)

Vincoli (Constraints) Multipli e Tabellari

Garantire che i dati nel database siano corretti allo strato più base ("data integrity") è fondamentale. Se la sicurezza la scrivi solo nell'applicazione NodeJS, i bug potrebbero causare dati inconsistenti nel DB. I vincoli (Constraints) a livello DDL sono l'ultima, impenetrabile linea di difesa.

I principali vincoli

Oltre a PRIMARY KEY (che rende una colonna univoca e NOT NULL) e ai classici NOT NULL e UNIQUE, esistono due categorie fondamentali per la consistenza logica del dato:

1. FOREIGN KEY (Integrità Referenziale)

Un vincolo REFERENCES assicura che un ID di collegamento esista davvero nella tabella "padre" in cui punta. Ad esempio, un ordine deve essere collegato a un cliente esistente.

SQL
CREATE TABLE orders (
  id SERIAL PRIMARY KEY,
  customer_id INTEGER REFERENCES customers(id)
);

Cosa fa la Foreign Key?

  • Ti impedisce di inserire un customer_id che non esiste in customers.
  • Ti impedisce di DELETE (eliminare) un cliente da customers se ci sono ordini che puntano a lui (protegge dai record "orfani").

Possiamo anche decidere cosa deve succedere quando il "padre" viene cancellato:

SQL
customer_id INTEGER REFERENCES customers(id) ON DELETE CASCADE

Con ON DELETE CASCADE, se cancelliamo il cliente, Postgres eliminerà automaticamente tutti gli orders collegati! (Da usare con grande cautela, di norma è meglio l'impostazione di base che blocca l'operazione).

2. CHECK Constraints

Un vincolo CHECK convalida la riga testando una espressione booleana prima di procedere al salvataggio.

SQL
CREATE TABLE contratti (
  id SERIAL PRIMARY KEY,
  stipendio NUMERIC(10,2) CHECK (stipendio > 0),
  data_inizio DATE,
  data_fine DATE,
  CHECK (data_fine > data_inizio)
);

Il primo CHECK è un vincolo di colonna (si riferisce solo a stipendio). Il secondo CHECK in fondo è un vincolo di tabella (può incrociare i valori di più colonne, e va dichiarato in fondo).

Se un INSERT o UPDATE prova a salvare la fine prima dell'inizio, Postgres lo rifiuterà con errore!

Nomenclature dei Constraint

Spesso è buona pratica dare un nome esplicito ai constraint (usando la keyword CONSTRAINT). In questo modo, quando Postgres blocca un record, l'errore ti dirà ad esempio "violato il vincolo 'stipendio_positivo'", molto più chiaro per far debug!

SQL
CREATE TABLE prodotti (
  id SERIAL PRIMARY KEY,
  nome VARCHAR(50),
  CONSTRAINT nome_univoco UNIQUE(nome)
);

Prova tu

Esercizio#sql.m9.l2.e1
Tentativi: 0Caricamento…

Crea una tabella 'prenotazioni' con id (SERIAL PRIMARY KEY) e un 'customer_id' (INTEGER). Usa CONSTRAINT fk_cliente FOREIGN KEY (customer_id) REFERENCES customers(id) per dare un nome esplicito al vincolo di Foreign Key. Fallo in fondo, come vincolo di tabella.

Caricamento editor…
Mostra suggerimento

Scrivi CONSTRAINT fk_cliente FOREIGN KEY (colonna_locale) REFERENCES tabella_esterna(col_esterna)

Soluzione disponibile dopo 3 tentativi

Vincoli con logica custom

Esercizio#sql.m9.l2.e2
Tentativi: 0Caricamento…

Crea una tabella 'eventi' con id (SERIAL PRIMARY KEY), posti_totali (INTEGER) e biglietti_venduti (INTEGER). Aggiungi un constraint di tabella chiamato 'check_capienza' dove i biglietti_venduti non devono mai essere maggiori dei posti_totali.

Caricamento editor…
Mostra suggerimento

Aggiungi il vincolo in fondo usando CONSTRAINT check_capienza CHECK ( espressione )

Soluzione disponibile dopo 3 tentativi