Nelle lezioni precedenti abbiamo visto come utilizzare WHERE per filtrare i dati e diverse funzioni per elaborare numeri, date e stringhe.
SQL permette di andare oltre le semplici condizioni e di produrre risultati diversi in base ai dati. Possiamo, ad esempio, assegnare una categoria a un prodotto in base al prezzo, mostrare un testo diverso a seconda dello stato di un utente oppure sostituire un valore NULL con un altro valore.
Per farlo possiamo utilizzare principalmente CASE, COALESCE(), IFNULL() e IF().
CASE permette di valutare una o più condizioni e di restituire un risultato diverso in base alla condizione verificata.
Esistono due forme principali di CASE: la sintassi Simple, che confronta una colonna con diversi valori, e la sintassi Searched, che permette di utilizzare condizioni più generiche.
La forma Simple di CASE confronta un'espressione con diversi valori.
La sintassi è:
CASE espressione
WHEN valore1 THEN risultato1
WHEN valore2 THEN risultato2
ELSE risultato_default
ENDPer esempio, supponiamo di avere una colonna stato che può contenere i valori 1, 2 o 3 e identifica lo stato di un utente:
SELECT nome,
CASE stato
WHEN 1 THEN 'Attivo'
WHEN 2 THEN 'Sospeso'
WHEN 3 THEN 'Eliminato'
ELSE 'Sconosciuto'
END AS descrizione_stato
FROM utenti;SQL confronta il valore di stato con ciascun valore indicato dopo WHEN. Se stato vale 1, restituisce Attivo; se vale 2, restituisce Sospeso; se vale 3, restituisce Eliminato.
ELSE è facoltativo in CASE e permette di indicare il risultato da restituire quando nessuna delle condizioni precedenti viene soddisfatta. Sapendo che stato può arrivare fino a 3, la query può essere riassunta così:
SELECT nome,
CASE stato
WHEN 1 THEN 'Attivo'
WHEN 2 THEN 'Sospeso'
ELSE 'Eliminato'
END AS descrizione_stato
FROM utenti;Se omettiamo ELSE e nessuna condizione viene soddisfatta, CASE restituisce NULL.
La forma Searched di CASE permette invece di utilizzare vere e proprie condizioni dopo WHEN.
La sintassi è:
CASE
WHEN condizione1 THEN risultato1
WHEN condizione2 THEN risultato2
ELSE risultato_default
ENDPer esempio, possiamo classificare i prodotti in base al loro prezzo:
SELECT nome, prezzo,
CASE
WHEN prezzo < 20 THEN 'Economico'
WHEN prezzo < 100 THEN 'Medio'
ELSE 'Costoso'
END AS categoria_prezzo
FROM prodotti;Nell'esempio:
prezzo è inferiore a 20, viene restituito Economico;prezzo è almeno 20 ma inferiore a 100, viene restituito Medio;Costoso.La forma Searched di CASE è particolarmente utile perché possiamo utilizzare operatori di confronto e condizioni (come quelle in JavaScript) anche complesse.
Le condizioni di un CASE vengono valutate dall'alto verso il basso. Quando viene trovata la prima condizione vera, SQL restituisce il relativo risultato e non valuta le condizioni successive.
Per questo motivo, è importante ordinarle correttamente. Ad esempio, questa query SQL restituirà sempre e solo Medio o Economico, mai Costoso:
SELECT prezzo,
CASE
WHEN prezzo >= 50 THEN 'Medio'
WHEN prezzo >= 100 THEN 'Costoso'
ELSE 'Economico'
END AS categoria
FROM prodotti;Ad esempio, un prodotto con un prezzo di 120 soddisfa già la prima condizione, quindi viene classificato come Medio e non come Costoso.
CASE non è una clausola indipendente come SELECT o WHERE: è un'espressione che possiamo inserire in diverse parti di una query.
L'utilizzo più comune di CASE è all'interno di SELECT, per creare un valore calcolato in base ai dati.
Per esempio:
SELECT nome, prezzo,
CASE
WHEN prezzo < 50 THEN 'Basso'
WHEN prezzo < 100 THEN 'Medio'
ELSE 'Alto'
END AS fascia_prezzo
FROM prodotti;In questo caso fascia_prezzo non è una colonna presente nella tabella: viene calcolata dalla query.
Possiamo utilizzare CASE anche insieme alle funzioni viste nelle lezioni precedenti:
SELECT nome,
CASE
WHEN CHAR_LENGTH(nome) > 10 THEN 'Nome lungo'
ELSE 'Nome breve'
END AS tipo_nome
FROM utenti;Possiamo utilizzare un'espressione CASE anche all'interno di WHERE, anche se spesso una normale combinazione di condizioni con AND e OR è più semplice e leggibile.
In questo caso la soglia del prezzo cambia in base alla categoria del prodotto:
SELECT * FROM prodotti
WHERE CASE
WHEN categoria = 'PC' THEN prezzo > 500
WHEN categoria = 'Tablet' THEN prezzo > 200
ELSE FALSE
END;Un altro utilizzo molto interessante è all'interno di ORDER BY. Possiamo utilizzare CASE per creare un ordinamento personalizzato.
Supponiamo, ad esempio, di voler mostrare prima gli utenti attivi, poi quelli sospesi e infine gli altri:
SELECT nome, stato
FROM utenti
ORDER BY CASE
WHEN stato = 'attivo' THEN 1
WHEN stato = 'sospeso' THEN 2
ELSE 3
END;SQL assegna temporaneamente un numero a ogni stato e utilizza questi numeri per stabilire l'ordine.
Possiamo anche combinare CASE con un secondo criterio. In questo esempio gli utenti vengono prima ordinati in base allo stato e, all'interno dello stesso stato, alfabeticamente per nome:
SELECT nome, stato FROM utenti
ORDER BY CASE
WHEN stato = 'attivo' THEN 1
WHEN stato = 'sospeso' THEN 2
ELSE 3
END,
nome ASC;Nella lezione sulle condizioni avanzate abbiamo visto che NULL rappresenta un valore assente o sconosciuto e che deve essere gestito con IS NULL e IS NOT NULL, anziché con = NULL.
Quando invece vogliamo sostituire un valore NULL con un valore alternativo, possiamo utilizzare COALESCE().
La sintassi è: COALESCE(valore1, valore2, valore3, ...) e la funzione restituisce il primo valore che non è NULL.
Ad esempio, se il numero di telefono di un utente non è disponibile:
SELECT nome, COALESCE(telefono, 'Non disponibile') AS telefono
FROM utenti;Nell'esempio, se telefono contiene un numero, viene mostrato quel numero. Se invece contiene NULL, viene mostrato Non disponibile.
Puoi anche usare diverse alternative in COALESCE():
SELECT nome, COALESCE(telefono, cellulare, 'Non disponibile') AS contatto
FROM utenti;SQL controllerà i valori nell'ordine: telefono, cellulare, e poi assegna Non disponibile.
MySQL mette a disposizione anche IFNULL(), una funzione specifica per gestire un singolo valore NULL. È una versione semplificata di COALESCE().
La sintassi è: IFNULL(valore, alternativa). Se valore non è NULL, viene restituito il valore originale. Se invece è NULL, viene restituita l'alternativa.
Vediamo un esempio:
SELECT nome, IFNULL(telefono, 'Non disponibile') AS telefono
FROM utenti;La differenza principale da COALESCE() è che IFNULL() accetta due argomenti, mentre COALESCE() può gestirne diversi.
MySQL mette a disposizione anche la funzione IF(), che permette di scegliere tra due risultati in base a una condizione.
La sintassi è: IF(condizione, valore_se_vero, valore_se_falso). Se condizione è TRUE, allora viene assegnato valore_se_vero, se è FALSE viene assegnato valore_se_falso.
Per esempio, possiamo usare IF() per restituire Maggiorenne o Minorenne in base a eta dell'utente:
SELECT nome, IF(eta >= 18, 'Maggiorenne', 'Minorenne') AS categoria
FROM utenti;