L’importanza di una storia: SQL e DB relazionali
Quando lavoriamo con i dati, stiamo raccontando una storia.
Clienti che acquistano prodotti. Studenti che sostengono esami. Conti che trasferiscono denaro.
Un database relazionale serve a mantenere questa storia ordinata, coerente e affidabile nel tempo.
SQL è il linguaggio con cui interroghiamo e modifichiamo quella storia.
Partiamo dalle fondamenta, poi saliamo gradualmente verso concetti più avanzati.
Il problema: organizzare il caos
Senza struttura, i dati si contraddicono:
- Due utenti con la stessa email.
- Un ordine senza cliente.
- Informazioni duplicate in più punti.
Il caos non esplode subito. Si insinua lentamente.
Un database nasce per imporre ordine.
Tabelle: la struttura della storia
Un database relazionale organizza i dati in tabelle.
Ogni tabella è composta da:
- Colonne (campi) → descrivono che tipo di informazione stiamo salvando.
- Righe (record) → rappresentano i singoli elementi.
Esempio:
Tabella utenti
| id | nome | |
|---|---|---|
| 1 | Paolo | paolo@email.it |
| 2 | Lucia | lucia@email.it |
Ogni riga è un record.
Ogni colonna è un campo.
La chiave primaria: l’identità del record
Di solito troviamo qualcosa del genere:
id SERIAL PRIMARY KEY
La PRIMARY KEY (chiave primaria):
- identifica ogni record in modo univoco
- non può essere NULL
- è il riferimento usato dalle altre tabelle
È la carta d’identità tecnica del record.
Può esistere una sola PRIMARY KEY per tabella legata per coerenza ad una o più FOREIGN KEY.
L’id è spesso un numero progressivo generato automaticamente.
È stabile, non cambia mai.
UNIQUE e NOT NULL: regole di coerenza
Ora introduciamo i vincoli.
NOT NULL
nome VARCHAR(100) NOT NULL
Significa: questo campo deve avere un valore.NULL in SQL non è una stringa vuota. È “assenza di valore”. È “non sappiamo”.
NOT NULL impedisce l’assenza di dato.
UNIQUE
email VARCHAR(255) UNIQUE
Significa: nessuna email può comparire due volte.
Qui stiamo imponendo una regola di non duplicazione.
Differenza tra PRIMARY KEY (id) e UNIQUE
Qui c’è una distinzione importante.
Entrambi impediscono duplicati. Ma non sono la stessa cosa.
PRIMARY KEY:
- definisce l’identità ufficiale del record
- è unica per tabella
- non può essere NULL
- è usata nelle relazioni tra tabelle
UNIQUE:
- impedisce duplicati su un campo
- può esistere su più colonne
- può essere usato solo come regola di validazione
Esempio:
id SERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
codice_fiscale VARCHAR(16) UNIQUE
Qui abbiamo:
- un identificatore tecnico (
id) - due campi che devono essere unici (email e codice fiscale)
Concettualmente:
- La PRIMARY KEY dice chi è il record.
- UNIQUE dice questa informazione non può ripetersi.
Un dettaglio interessante:
UNIQUE, nello standard SQL, permette più valori NULL (perché NULL significa “sconosciuto” e due valori sconosciuti non sono considerati uguali).
La PRIMARY KEY invece non permette NULL.
È una differenza sottile ma fondamentale.
Le relazioni: collegare le storie
Creiamo una seconda tabella:
CREATE TABLE ordini (
id SERIAL PRIMARY KEY,
utente_id INTEGER REFERENCES utenti(id),
prodotto VARCHAR(100)
);
utente_id è una chiave esterna (FOREIGN KEY).
Significa:
“Questo valore deve esistere come id nella tabella utenti.”
Ora il database impedisce ordini “orfani”.
Le relazioni garantiscono coerenza tra tabelle diverse.
JOIN: quando le storie si incontrano
SELECT utenti.nome, ordini.prodotto
FROM utenti
JOIN ordini ON utenti.id = ordini.utente_id;
Il JOIN collega record di tabelle diverse sulla base delle chiavi.
Questo è il cuore del modello relazionale:
insiemi collegati da regole precise.
Integrità referenziale: protezione avanzata
Possiamo anche dire cosa succede se un utente viene cancellato:
FOREIGN KEY (utente_id)
REFERENCES utenti(id)
ON DELETE CASCADE
Significa: se un utente viene eliminato, anche i suoi ordini vengono eliminati automaticamente.
Questa si chiama integrità referenziale.
Il database non si limita a memorizzare dati.
Difende le relazioni tra i dati.
Indici: quando i dati crescono
Con milioni di record, cercare diventa costoso.
Un indice è una struttura interna (spesso un B-tree) che permette ricerche rapide.
CREATE INDEX idx_email ON utenti(email);
Senza indice → scansione completa.
Con indice → accesso diretto.
Ma ogni indice:
- occupa spazio
- rallenta INSERT e UPDATE
Ogni ottimizzazione ha un prezzo.
Transazioni e proprietà ACID
Immagina un pagamento online.
BEGIN;
UPDATE conti SET saldo = saldo - 100 WHERE id = 1;
UPDATE conti SET saldo = saldo + 100 WHERE id = 2;
COMMIT;
Se qualcosa fallisce prima del COMMIT, si fa ROLLBACK.
Le transazioni rispettano le proprietà ACID:
- Atomicità → tutto o niente
- Consistenza → rispetto dei vincoli
- Isolamento → operazioni concorrenti non si interferiscono
- Durabilità → una volta confermato, il dato resta
Questo è il motivo per cui le banche usano database relazionali.
Aggregazioni e analisi
SQL non serve solo a salvare dati.
SELECT utente_id, COUNT(*)
FROM ordini
GROUP BY utente_id;
“Quanti ordini ha fatto ogni utente?”
Possiamo anche calcolare medie, somme, classifiche.
Con le window functions possiamo fare analisi più sofisticate mantenendo il dettaglio delle righe.
Normalizzazione: progettare prima di scrivere
Se salviamo lo stesso dato in 10 posti diversi, prima o poi diverge.
La normalizzazione aiuta a:
- eliminare ridondanze inutili
- prevenire anomalie
- mantenere coerenza logica
Non è teoria accademica. È igiene progettuale.
Sicurezza e controllo
Un database reale permette di:
- creare utenti con permessi diversi
- limitare chi può leggere o scrivere
- registrare operazioni
Non è solo archiviazione. È infrastruttura critica.
Perché SQL è ancora centrale
SQL esiste dagli anni ’70.
Eppure è ancora ovunque.
Perché unisce:
- rigore matematico (algebra relazionale)
- praticità ingegneristica
- controllo della coerenza
- ottimizzazione automatica
Il modello relazionale separa chiaramente:
- identità (PRIMARY KEY)
- validazione (UNIQUE, NOT NULL)
- relazione (FOREIGN KEY)
- accesso (SELECT)
È un sistema elegante perché ogni concetto ha un ruolo preciso.
Conclusione
Un database relazionale non è solo un contenitore di dati.
È un sistema di regole che protegge la verità della storia.
Le tabelle danno struttura.
Le chiavi danno identità.
I vincoli difendono la coerenza.
Le relazioni collegano le informazioni.
Le transazioni proteggono le operazioni critiche.
Imparare SQL significa imparare a costruire sistemi affidabili.
E costruire sistemi affidabili significa saper organizzare il caos in modo rigoroso.
È una competenza tecnica, certo.
Ma è anche una forma di disciplina mentale: trasformare informazioni sparse in una narrazione coerente e verificabile nel tempo.
aggiungi il create delete, drop, alter…
Perfetto. Completiamo la storia aggiungendo i comandi che permettono non solo di usare le tabelle… ma di crearle, modificarle e distruggerle. Perché un database non è immobile: evolve.
Integro questa parte nell’articolo come se fosse un nuovo capitolo naturale.
Creare la struttura: CREATE
Prima di inserire dati, dobbiamo creare la tabella.
CREATE TABLE utenti (
id SERIAL PRIMARY KEY,
nome VARCHAR(100) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL
);
Qui stiamo definendo:
- le colonne (campi)
- i tipi di dato
- i vincoli (PRIMARY KEY, UNIQUE, NOT NULL)
CREATE serve a costruire la struttura.
È il momento in cui progettiamo la forma della storia.
Possiamo anche creare un indice:
CREATE INDEX idx_email ON utenti(email);
Oppure creare un database intero:
CREATE DATABASE negozio;
CREATE è il comando della nascita.
Modificare la struttura: ALTER
Nel mondo reale, i requisiti cambiano.
Serve aggiungere una colonna?
Cambiare un vincolo?
Si usa ALTER.
Aggiungere una colonna:
ALTER TABLE utenti
ADD COLUMN data_registrazione DATE;
Rendere obbligatorio un campo:
ALTER TABLE utenti
ALTER COLUMN nome SET NOT NULL;
Aggiungere un vincolo UNIQUE dopo la creazione:
ALTER TABLE utenti
ADD CONSTRAINT email_unica UNIQUE (email);
ALTER è il comando dell’evoluzione.
Permette di modificare la struttura senza distruggere tutto.
Cancellare dati: DELETE
DELETE rimuove righe (record), ma lascia intatta la struttura.
DELETE FROM utenti
WHERE id = 2;
Qui stiamo eliminando un utente specifico.
Senza WHERE:
DELETE FROM utenti;
Vengono eliminate tutte le righe, ma la tabella resta.
Struttura intatta. Dati spariti.
È una differenza fondamentale.
Eliminare la struttura: DROP
DROP è più radicale.
DROP TABLE utenti;
Qui non stiamo cancellando i record.
Stiamo cancellando la tabella intera.
Struttura + dati → eliminati.
Si può fare anche:
DROP DATABASE negozio;
Questo è l’equivalente informatico del “demoliamo l’edificio”.
DROP è irreversibile (a meno di backup).
Differenza tra DELETE e DROP
È una distinzione cruciale:
DELETE→ elimina i dati (righe), mantiene la tabella.DROP→ elimina la tabella stessa.
Uno agisce sul contenuto.
L’altro sulla struttura.
Un altro comando utile: TRUNCATE
Vale la pena citarlo.
TRUNCATE TABLE utenti;
Elimina tutte le righe molto velocemente, ma mantiene la struttura.
È più veloce di DELETE senza WHERE, ma meno flessibile.
DDL vs DML: due categorie di comandi
Ora possiamo fare una distinzione più tecnica.
In SQL esistono due grandi famiglie:
DDL (Data Definition Language)
Definisce la struttura:
- CREATE
- ALTER
- DROP
DML (Data Manipulation Language)
Manipola i dati:
- SELECT
- INSERT
- UPDATE
- DELETE
Questa separazione riflette una distinzione profonda:
- La struttura definisce la forma della storia.
- I dati riempiono quella forma.
Mettere tutto insieme
Ora la visione è completa.
Un database relazionale è composto da:
- Tabelle (struttura)
- Righe (record)
- Colonne (campi)
- Chiavi primarie (identità)
- Vincoli UNIQUE e NOT NULL (coerenza)
- Chiavi esterne (relazioni)
- Indici (prestazioni)
- Transazioni (affidabilità)
E SQL ci permette di:
- creare (CREATE)
- modificare (ALTER)
- interrogare (SELECT)
- inserire (INSERT)
- aggiornare (UPDATE)
- cancellare dati (DELETE)
- eliminare strutture (DROP)
Non è solo un linguaggio.
È un sistema completo per costruire e mantenere mondi informativi coerenti.
E più si va avanti, più si capisce una cosa:
la vera potenza non è nei singoli comandi, ma nella disciplina che impongono. Struttura, regole, relazioni.
È questo che rende i database relazionali ancora oggi una delle invenzioni più solide e durature dell’informatica moderna.
scrivi il tutto assieme
L’importanza di una storia: SQL e DB relazionali
Quando lavoriamo con i dati, stiamo raccontando una storia.
Clienti che acquistano prodotti. Studenti che sostengono esami. Conti che trasferiscono denaro.
Un database relazionale esiste per mantenere questa storia ordinata, coerente e affidabile nel tempo.
SQL è il linguaggio che ci permette di costruirla, interrogarla, modificarla e proteggerla.
Partiamo dalle basi. Poi saliamo gradualmente verso concetti più avanzati.
Il problema: organizzare il caos
Senza struttura, i dati diventano contraddittori:
- Due utenti con la stessa email
- Un ordine senza cliente
- Informazioni duplicate in più punti
Il caos nei dati non è spettacolare. È silenzioso. E si manifesta quando è troppo tardi.
Un database nasce per imporre regole.
Tabelle: la struttura della storia
Un database relazionale organizza i dati in tabelle.
Ogni tabella è composta da:
- Colonne (campi) → descrivono che tipo di informazione stiamo salvando.
- Righe (record) → rappresentano i singoli elementi.
Esempio:
| id | nome | |
|---|---|---|
| 1 | Paolo | paolo@email.it |
| 2 | Lucia | lucia@email.it |
Ogni riga è un record.
Ogni colonna è un campo.
Creare la struttura: CREATE
Prima di salvare dati, dobbiamo definire la struttura.
CREATE TABLE utenti (
id SERIAL PRIMARY KEY,
nome VARCHAR(100) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL
);
Qui stiamo definendo:
- le colonne
- il tipo di dato (VARCHAR, ecc.)
- i vincoli
CREATE serve a costruire la forma della storia.
Possiamo anche creare un database:
CREATE DATABASE negozio;
Identità: PRIMARY KEY
La riga:
id SERIAL PRIMARY KEY
definisce la chiave primaria.
La PRIMARY KEY:
- identifica ogni record in modo univoco
- non può essere NULL
- è il riferimento usato dalle altre tabelle
È la carta d’identità tecnica del record.
Ogni tabella può avere una sola PRIMARY KEY.
L’id è spesso un numero generato automaticamente. È stabile e non cambia.
Regole di coerenza: NOT NULL e UNIQUE
Un database serio non memorizza qualsiasi cosa. Impone regole.
NOT NULL
nome VARCHAR(100) NOT NULL
Significa: questo campo deve avere un valore.
In SQL, NULL non è una stringa vuota. È “assenza di valore”.
NOT NULL impedisce quella assenza.
UNIQUE
email VARCHAR(255) UNIQUE
Significa: nessuna email può comparire due volte.
Evita duplicati.
Differenza tra PRIMARY KEY e UNIQUE
A prima vista sembrano simili. Entrambi impediscono duplicati. Ma il loro ruolo è diverso.
PRIMARY KEY:
- definisce l’identità ufficiale del record
- è unica per tabella
- non può essere NULL
- viene usata nelle relazioni
UNIQUE:
- è un vincolo di validazione
- impedisce duplicazioni
- può esistere su più colonne
- può permettere NULL (dipende dal database, ma nello standard sì)
Esempio:
id SERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
codice_fiscale VARCHAR(16) UNIQUE
Qui:
idè l’identità tecnicaemailecodice_fiscalesono campi che non devono duplicarsi
Concettualmente:
- La PRIMARY KEY dice chi è il record.
- UNIQUE dice questa informazione non può ripetersi.
Separare identità e regole è una scelta progettuale elegante.
Inserire, aggiornare, cancellare dati
Una volta creata la struttura, possiamo lavorare sui dati.
Inserire:
INSERT INTO utenti (nome, email)
VALUES ('Marco', 'marco@email.it');
Aggiornare:
UPDATE utenti
SET email = 'nuova@email.it'
WHERE id = 1;
Cancellare record:
DELETE FROM utenti
WHERE id = 2;
DELETE elimina le righe, ma lascia la tabella.
Eliminare la struttura: DROP
Se vogliamo eliminare completamente la tabella:
DROP TABLE utenti;
Qui spariscono sia struttura che dati.
Differenza fondamentale:
DELETE→ elimina i datiDROP→ elimina la struttura
Uno agisce sul contenuto. L’altro sull’esistenza stessa della tabella.
Modificare la struttura: ALTER
I requisiti cambiano. Il database evolve.
Aggiungere una colonna:
ALTER TABLE utenti
ADD COLUMN data_registrazione DATE;
Aggiungere un vincolo:
ALTER TABLE utenti
ADD CONSTRAINT email_unica UNIQUE (email);
ALTER permette di modificare la struttura senza distruggerla.
Le relazioni: collegare le storie
Creiamo una seconda tabella:
CREATE TABLE ordini (
id SERIAL PRIMARY KEY,
utente_id INTEGER REFERENCES utenti(id),
prodotto VARCHAR(100)
);
utente_id è una chiave esterna.
Significa: questo valore deve esistere come id nella tabella utenti.
Ora il database impedisce ordini senza utente.
JOIN: unire i dati
SELECT utenti.nome, ordini.prodotto
FROM utenti
JOIN ordini ON utenti.id = ordini.utente_id;
Il JOIN collega record di tabelle diverse.
È il momento in cui le storie si incontrano.
Indici: velocità su larga scala
Con milioni di record, cercare diventa costoso.
CREATE INDEX idx_email ON utenti(email);
Un indice permette ricerche più veloci.
Ma ogni indice:
- occupa spazio
- rallenta scritture
Ogni ottimizzazione ha un costo.
Transazioni: proteggere le operazioni
Immagina un trasferimento di denaro:
BEGIN;
UPDATE conti SET saldo = saldo - 100 WHERE id = 1;
UPDATE conti SET saldo = saldo + 100 WHERE id = 2;
COMMIT;
Se qualcosa fallisce prima del COMMIT, si può fare ROLLBACK.
Le transazioni rispettano le proprietà ACID:
- Atomicità
- Consistenza
- Isolamento
- Durabilità
Questo garantisce affidabilità.
Aggregazioni e analisi
SQL non serve solo a salvare dati. Serve a estrarre informazioni.
SELECT utente_id, COUNT(*)
FROM ordini
GROUP BY utente_id;
“Quanti ordini ha fatto ogni utente?”
Con funzioni più avanzate (come le window functions) possiamo fare classifiche, medie mobili, numerazioni per gruppo.
DDL e DML: due categorie
Possiamo distinguere:
DDL (Data Definition Language)
Definisce la struttura:
- CREATE
- ALTER
- DROP
DML (Data Manipulation Language)
Manipola i dati:
- SELECT
- INSERT
- UPDATE
- DELETE
Struttura e contenuto sono due livelli distinti.
Ed è questa separazione che rende il sistema robusto.
Conclusione
Un database relazionale non è solo un archivio. È un sistema di regole.
Le tabelle danno forma.
Le chiavi danno identità.
I vincoli difendono la coerenza.
Le relazioni collegano le informazioni.
Gli indici migliorano le prestazioni.
Le transazioni proteggono le operazioni critiche.
SQL è lo strumento che governa tutto questo.
Impararlo significa imparare a organizzare il caos con metodo.
E quando si padroneggiano identità, regole e relazioni, si capisce che un database ben progettato non è solo tecnico. È una struttura logica che mantiene la verità dei dati nel tempo.