Probabilmente ti sei già imbattuto in espressioni condizionali nei linguaggi di programmazione: if-else, switch-case e robe simili. In SQL c'è uno strumento tutto suo per lavorare con le condizioni: l'espressione CASE. Ti permette di prendere decisioni direttamente nelle query: se la condizione è vera, fai una cosa, se non lo è — fanne un'altra.
La struttura CASE è particolarmente utile quando devi lavorare con dati che possono avere valori NULL. La sintassi è semplice, tipo bigino, guarda qui:
CASE
WHEN condizione1 THEN risultato1
WHEN condizione2 THEN risultato2
...
ELSE risultato_predefinito
END
Ha senso, vero? "Se succede questo, fai quello, altrimenti fai qualcos'altro". Facile da ricordare: "WHEN — è il se, THEN — è cosa fare, ELSE — è cosa fare se niente va bene".
Esempio: classificazione dei prodotti
Immagina di avere una tabella products con una colonna price, e vuoi dividere i prodotti in gruppi in base al loro prezzo.
| id | name | price |
|---|---|---|
| 1 | Magic Wand | 120 |
| 2 | Potion Set | 45 |
| 3 | Crystal Ball | 75 |
| 4 | Enchanted Map | NULL |
| 5 | Broomstick | 99 |
| 6 | Spell Book | 180 |
SELECT
name AS product_name,
price,
CASE
WHEN price IS NULL THEN 'Sconosciuto'
WHEN price < 50 THEN 'Economico'
WHEN price BETWEEN 50 AND 100 THEN 'Standard'
ELSE 'Premium'
END AS price_category
FROM products;
Cosa succede qui?
- Se il prezzo
pricedel prodotto non è specificatoNULL, mostriamo la categoria come'Sconosciuto'. - Se il prezzo è minore di 50, il prodotto è considerato economico
'Economico'. - Se il prezzo è tra 50 e 100, va nella categoria
'Standard'. - Tutto il resto — sono prodotti di fascia alta
'Premium'.
Ecco il risultato:
| product_name | price | price_category |
|---|---|---|
| Magic Wand | 120 | Premium |
| Potion Set | 45 | Economico |
| Crystal Ball | 75 | Standard |
| Enchanted Map | NULL | Sconosciuto |
| Broomstick | 99 | Standard |
| Spell Book | 180 | Premium |
SQL, come un mago, legge le righe della tabella products, le passa una a una e le classifica in modo furbo.
Lavorare con NULL in CASE WHEN
Capita spesso che nei dati ci siano valori mancanti (ciao, NULL), e bisogna sostituirli con qualcosa. Per esempio, abbiamo una tabella users con la colonna email, e per gli utenti senza email vogliamo mostrare 'Non specificato'.
| user_id | name | |
|---|---|---|
| 1 | Alex Lin | alex@example.com |
| 2 | Maria Chi | NULL |
| 3 | Anna Song | anna@magic.com |
| 4 | Otto Art | NULL |
| 5 | John Smith | john@wizard.org |
SELECT
user_id,
name,
CASE
WHEN email IS NULL THEN 'Non specificato'
ELSE email
END AS email_address
FROM users;
| user_id | name | email_address |
|---|---|---|
| 1 | Alex Lin | alex@example.com |
| 2 | Maria Chi | Non specificato |
| 3 | Anna Song | anna@magic.com |
| 4 | Otto Art | Non specificato |
| 5 | John Smith | john@wizard.org |
Qui SQL fa un po' lo sciamano, rianimando le righe mezze vuote. Se manca l'email, la sostituisce con 'Non specificato'. Se c'è — la lascia così com'è.
Espressioni condizionali con i numeri
A volte non basta solo sostituire i valori, ma serve anche costruire una logica nuova. Per esempio, supponiamo di avere una tabella students con le colonne score (voto) e name.
| name | score |
|---|---|
| Alex Lin | 95 |
| Maria Chi | 82 |
| Anna Song | 48 |
| Otto Art | NULL |
| John Smith | 67 |
| Zoe Black | 30 |
Vogliamo valutare gli studenti come "Eccellente", "Passato" e "Bocciato", in base ai loro punti.
SELECT
name AS student_name,
score,
CASE
WHEN score IS NULL THEN 'Nessun voto'
WHEN score >= 90 THEN 'Eccellente'
WHEN score >= 50 THEN 'Passato'
ELSE 'Bocciato'
END AS performance_category
FROM students;
| student_name | score | performance_category |
|---|---|---|
| Alex Lin | 95 | Eccellente |
| Maria Chi | 82 | Passato |
| Anna Song | 48 | Bocciato |
| Otto Art | NULL | Nessun voto |
| John Smith | 67 | Passato |
| Zoe Black | 30 | Bocciato |
SQL distribuisce gentilmente gli studenti, come un esaminatore severo: 90 punti e oltre — solo "Eccellente", da 50 in su — "Passato". Se i punti non bastano... beh, hai capito.
Raggruppamento e gestione dei NULL
Lavorare con gruppi di dati — è un altro campo dove CASE WHEN dà il meglio. Immagina di avere una tabella orders, e vuoi contare il numero totale di ordini per stato, inclusi quelli con stato NULL.
| order_id | status |
|---|---|
| 1 | Completed |
| 2 | Pending |
| 3 | NULL |
| 4 | Shipped |
| 5 | Completed |
| 6 | NULL |
| 7 | Pending |
| 8 | Completed |
| 9 | Shipped |
| 10 | NULL |
SELECT
CASE
WHEN status IS NULL THEN 'Nessuno stato'
ELSE status
END AS order_status,
COUNT(*)
FROM orders
GROUP BY
CASE
WHEN status IS NULL THEN 'Nessuno stato'
ELSE status
END;
Questa query gestisce con cura gli stati vuoti NULL e mette 'Nessuno stato' al loro posto, contando anche il numero totale di ordini in ogni gruppo. Ecco il risultato:
| order_status | count |
|---|---|
| Completed | 3 |
| Pending | 2 |
| Shipped | 2 |
| Nessuno stato | 3 |
Casi pratici: "Trucchi" con CASE WHEN
Esempio 1: Ordinamento considerando i NULL
A volte i valori NULL devono essere mostrati o all'inizio o alla fine di una lista ordinata. Questo si usa spesso, ad esempio, nelle liste di task, dove i task prioritari devono stare in alto, e quelli senza priorità (NULL) in fondo.
| task_id | task_name | priority |
|---|---|---|
| 1 | Fix bugs | 1 |
| 2 | Update documentation | 3 |
| 3 | Plan sprint | NULL |
| 4 | Code review | 2 |
| 5 | Organize meeting | NULL |
| 6 | Deploy release | 1 |
SELECT
task_name,
priority,
CASE
WHEN priority IS NULL THEN 1
ELSE 0
END AS priority_sort
FROM tasks
ORDER BY priority_sort ASC, priority ASC;
Qui abbiamo aggiunto una colonna "virtuale" priority_sort, che mette i valori NULL in fondo a tutto, e gli altri li ordina in modo crescente.
| task_name | priority | priority_sort |
|---|---|---|
| Deploy release | 1 | 0 |
| Fix bugs | 1 | 0 |
| Code review | 2 | 0 |
| Update documentation | 3 | 0 |
| Plan sprint | NULL | 1 |
| Organize meeting | NULL | 1 |
Esempio 2: Calcoli considerando i NULL
Ora immagina che stiamo calcolando il totale di un ordine nella tabella orders, dove nella colonna discount lo sconto può essere NULL se non c'è.
| order_id | total_price | discount |
|---|---|---|
| 101 | 100 | 10 |
| 102 | 200 | NULL |
| 103 | 150 | 15 |
| 104 | 120 | NULL |
| 105 | 80 | 5 |
Qui dobbiamo sostituire NULL con 0, così il calcolo non si rompe.
SELECT
order_id,
total_price,
discount,
total_price -
CASE
WHEN discount IS NULL THEN 0
ELSE discount
END AS final_price
FROM orders;
| order_id | total_price | discount | final_price |
|---|---|---|---|
| 101 | 100 | 10 | 90 |
| 102 | 200 | NULL | 200 |
| 103 | 150 | 15 | 135 |
| 104 | 120 | NULL | 120 |
| 105 | 80 | 5 | 75 |
Questo trucchetto magico con CASE ci fa stare tranquilli che NULL non rovinerà i calcoli matematici.
Per orderid = 101: discount = 10. finalprice = 100 - 10 = 90. Per orderid = 102: discount = NULL. CASE restituisce 0. finalprice = 200 - 0 = 200. Per orderid = 103: discount = 15. finalprice = 150 - 15 = 135. Per orderid = 104: discount = NULL. CASE restituisce 0. finalprice = 120 - 0 = 120. Per orderid = 105: discount = 5. finalprice = 80 - 5 = 75.
Esempio 3: Mostrare status utente personalizzati
Nella vita di tutti i giorni capita di dover mostrare lo stato di un utente (tipo "Attivo" o "In attesa") o segnalare che mancano dati. Per esempio, nella tabella users c'è la colonna last_login, dove si salva la data dell'ultimo accesso.
| user_id | name | last_login |
|---|---|---|
| 1 | Alex Lin | 2024-12-10 |
| 2 | Maria Chi | 2025-04-20 |
| 3 | Anna Song | NULL |
| 4 | Otto Art | 2025-05-01 |
| 5 | Liam Park | 2025-05-25 |
SELECT
user_id,
name,
CASE
WHEN last_login IS NULL THEN 'Mai loggato'
WHEN last_login < CURRENT_DATE - INTERVAL '30 days' THEN 'Inattivo'
ELSE 'Attivo'
END AS user_status
FROM users;
Con questa query il sistema admin prende vita: gli utenti senza accesso vengono chiamati "Mai loggato", quelli che non entrano da un po' sono "Inattivo". Gli altri sono attivi!
| user_id | name | user_status |
|---|---|---|
| 1 | Alex Lin | Inattivo |
| 2 | Maria Chi | Inattivo |
| 3 | Anna Song | Mai loggato |
| 4 | Otto Art | Inattivo |
| 5 | Liam Park | Attivo |
Errori comuni e come evitarli
Dimenticare ELSE: Se non aggiungi ELSE, SQL ti restituisce semplicemente NULL se nessuna condizione è soddisfatta. Non sempre è quello che vuoi. Quindi meglio specificare sempre ELSE, anche se sei sicuro di aver coperto tutti i casi.
CASE
WHEN condition THEN result
-- ELSE 'Valore predefinito' -- non dimenticare!
END
Condizioni complesse senza parentesi: Se hai più condizioni complesse con AND, OR o NOT, usa sempre le parentesi. Senza di loro la tua query potrebbe "pensare" male.
CASE
WHEN (column1 IS NOT NULL AND column2 > 5) THEN 'Valido'
ELSE 'Non valido'
END
Lavorare con NULL: Ricorda che NULL non è mai uguale (=) a qualcosa. Per esempio:
CASE
WHEN column = NULL THEN 'Nope!' -- Errore!
WHEN column IS NULL THEN 'Corretto!' -- Questo sì che va bene.
END
GO TO FULL VERSION