Lezioni del modulo (4/4)
Filtrare i gruppi: HAVING
Una volta che hai un risultato per gruppo (lezione precedente), spesso vuoi
tenere solo i gruppi che soddisfano una condizione: i dipartimenti con
più di 2 persone, i progetti con budget medio sopra 100k, gli utenti con
almeno 10 ordini. Per fare questo WHERE non basta.
Perché non basta WHERE
WHERE filtra le righe della tabella, prima dell'aggregazione. Quindi
non può vedere il risultato di COUNT(*) o AVG(...): nel momento in cui
WHERE agisce, quei valori non sono ancora stati calcolati.
-- ERRORE: COUNT(*) non esiste ancora quando WHERE viene valutato
SELECT department_id, COUNT(*) AS count
FROM employees
WHERE COUNT(*) > 2 -- ❌ non funziona
GROUP BY department_id;Per filtrare dopo l'aggregazione c'è una clausola apposita: HAVING.
La sintassi
SELECT colonna_di_raggruppamento, FUNZIONE_AGGREGATA(...)
FROM tabella
GROUP BY colonna_di_raggruppamento
HAVING condizione_sull_aggregato;-- Dipartimenti con più di 2 dipendenti:
SELECT department_id, COUNT(*) AS count
FROM employees
GROUP BY department_id
HAVING COUNT(*) > 2;HAVING è a GROUP BY quello che WHERE è a FROM: la stessa idea
("filtra"), ma applicata dopo il raggruppamento, sull'aggregato.
L'ordine logico delle clausole
Per non confondere mai più WHERE e HAVING, ricorda l'ordine in cui SQL
le esegue mentalmente:
FROM/JOIN— costruisce la tabella di partenza unendo sorgenti.WHERE— scarta le righe che non interessano.GROUP BY— raccoglie le righe rimaste in gruppi.HAVING— scarta i gruppi che non interessano.SELECT— calcola le colonne finali (compresi gli aggregati).ORDER BY/LIMIT— riordina e taglia.
Note importanti:
- in
WHEREpuoi usare solo colonne della tabella; - in
HAVINGpuoi usare colonne di raggruppamento e aggregati.
-- Combo classica: filtra prima, raggruppa, filtra i gruppi, ordina.
SELECT d.name, AVG(e.salary) AS average
FROM employees AS e
JOIN departments AS d ON e.department_id = d.id
WHERE e.hired_on >= '2018-01-01' -- filtra righe
GROUP BY d.name
HAVING AVG(e.salary) > 35000 -- filtra gruppi
ORDER BY average DESC;Prova tu
Per ogni dipartimento, mostra il nome (departments.name) e il numero di dipendenti, MA solo per i dipartimenti con almeno 2 dipendenti. Due colonne, una riga per dipartimento qualificato.
Mostra suggerimento
La condizione 'almeno 2' diventa COUNT(*) >= 2 in HAVING.
Soluzione disponibile dopo 3 tentativi
Esercizio di ripasso
Mostra i dipartimenti (departments.name) il cui stipendio medio supera 35000. Considera solo i dipendenti assunti dal 2018 in poi. Due colonne: name e la media. Ordina per media decrescente.
Mostra suggerimento
WHERE filtra le righe (dipendenti assunti dal 2018), HAVING filtra i gruppi (media > 35000).
Soluzione disponibile dopo 3 tentativi