Vai al contenuto
eLearner.app
Modulo 3 · Lezione 4 di 412/57 nel corso~8 min
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.

SQL
-- 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

SQL
SELECT colonna_di_raggruppamento, FUNZIONE_AGGREGATA(...)
FROM   tabella
GROUP BY colonna_di_raggruppamento
HAVING   condizione_sull_aggregato;
SQL
-- 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:

  1. FROM / JOIN — costruisce la tabella di partenza unendo sorgenti.
  2. WHERE — scarta le righe che non interessano.
  3. GROUP BY — raccoglie le righe rimaste in gruppi.
  4. HAVING — scarta i gruppi che non interessano.
  5. SELECT — calcola le colonne finali (compresi gli aggregati).
  6. ORDER BY / LIMIT — riordina e taglia.

Note importanti:

  • in WHERE puoi usare solo colonne della tabella;
  • in HAVING puoi usare colonne di raggruppamento e aggregati.
SQL
-- 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

Esercizio#sql.m3.l4.e1
Tentativi: 0Caricamento…

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.

Caricamento editor…
Mostra suggerimento

La condizione 'almeno 2' diventa COUNT(*) >= 2 in HAVING.

Soluzione disponibile dopo 3 tentativi

Esercizio di ripasso

Esercizio#sql.m3.l4.e2
Tentativi: 0Caricamento…

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.

Caricamento editor…
Mostra suggerimento

WHERE filtra le righe (dipendenti assunti dal 2018), HAVING filtra i gruppi (media > 35000).

Soluzione disponibile dopo 3 tentativi