Nella lezione precedente abbiamo visto come utilizzare GROUP BY per raggruppare le righe e applicare funzioni di aggregazione come COUNT() e AVG() a ciascun gruppo.
A questo punto potremmo aver bisogno di fare qualcosa in più: non vogliamo necessariamente visualizzare tutti i gruppi, ma soltanto quelli che rispettano una determinata condizione.
Per esempio, potremmo voler ottenere soltanto le categorie che contengono almeno 10 prodotti in un database, oppure i clienti che hanno effettuato ordini per un valore complessivo superiore a 1.000 euro.
Per filtrare i risultati dopo il raggruppamento possiamo utilizzare la clausola HAVING.
La clausola HAVING permette di filtrare i gruppi creati da GROUP BY.
Ad esempio, in un database di un negozio, supponiamo di voler visualizzare solo le categorie con almeno 10 prodotti:
SELECT categoria, COUNT(*) AS numero_prodotti
FROM prodotti
GROUP BY categoria
HAVING COUNT(*) >= 10;Prima GROUP BY crea un gruppo per ogni categoria e COUNT(*) conta i prodotti di ciascun gruppo. Successivamente, HAVING mantiene soltanto i gruppi in cui il conteggio è almeno 10.
HAVING può essere utilizzato con tutte le principali funzioni di aggregazione, che abbiamo visto nella lezione dedicata sulle funzioni.
Per esempio, possiamo mostrare soltanto le categorie il cui prezzo medio supera 100:
SELECT categoria, AVG(prezzo) AS prezzo_medio
FROM prodotti
GROUP BY categoria
HAVING AVG(prezzo) > 100;Possiamo anche utilizzare più condizioni:
SELECT categoria,
COUNT(*) AS numero_prodotti,
AVG(prezzo) AS prezzo_medio
FROM prodotti
GROUP BY categoria
HAVING COUNT(*) >= 10
AND AVG(prezzo) > 50;Una categoria deve quindi rispettare entrambe le condizioni per essere inclusa nel risultato.
WHERE e HAVING possono sembrare simili perché entrambi permettono di filtrare i dati, ma vengono utilizzati in momenti diversi e hanno uno scopo diverso.
WHERE viene utilizzato per filtrare le singole righe prima del raggruppamento.
Per esempio:
SELECT categoria, COUNT(*) AS numero_prodotti
FROM prodotti
WHERE prezzo >= 50
GROUP BY categoria;In questo caso WHERE elimina prima tutti i prodotti con un prezzo inferiore a 50. Successivamente, GROUP BY raggruppa soltanto i prodotti rimasti e COUNT(*) li conta.
Quindi WHERE stabilisce quali righe partecipano all'aggregazione.
HAVING, invece, viene applicato dopo il raggruppamento.
Prendiamo un esempio simile a quello precedente:
SELECT categoria, COUNT(*) AS numero_prodotti
FROM prodotti
GROUP BY categoria
HAVING COUNT(*) >= 10;Qui tutti i prodotti partecipano inizialmente al raggruppamento. Solo dopo aver calcolato il numero di prodotti per ogni categoria, HAVING elimina i gruppi con meno di 10 prodotti.
Possiamo anche utilizzare WHERE e HAVING nella stessa query:
SELECT categoria,
COUNT(*) AS numero_prodotti,
AVG(prezzo) AS prezzo_medio
FROM prodotti
WHERE prezzo >= 50
GROUP BY categoria
HAVING COUNT(*) >= 10;La query nell'esempio funziona in questo modo:
WHERE elimina i prodotti con prezzo inferiore a 50.GROUP BY raggruppa quelli rimasti per categoria.COUNT() conta i prodotti di ogni categoria.HAVING mantiene soltanto le categorie con almeno 10 prodotti.Quando non usare WHERE al posto di HAVING?
In alcuni casi non è possibile spostare la condizione di HAVING in WHERE. In generale, le condizioni che dipendono dai risultati delle funzioni di aggregazione appartengono normalmente a HAVING.
Consideriamo, ad esempio, la seguente query:
-- Non corretto
SELECT categoria, COUNT(*)
FROM prodotti
WHERE COUNT(*) >= 10
GROUP BY categoria;COUNT(*) >= 10 in WHERE, perché COUNT(*) viene calcolato sui gruppi, mentre WHERE viene applicato prima che questi gruppi vengano creati.Per comprendere meglio la differenza tra WHERE e HAVING, è utile conoscere l'ordine logico con cui MySQL elabora una query.
Una query può essere scritta, ad esempio, in questo ordine:
SELECT categoria, COUNT(*) AS numero_prodotti
FROM prodotti
WHERE prezzo >= 50
GROUP BY categoria
HAVING COUNT(*) >= 10
ORDER BY numero_prodotti DESC
LIMIT 5;Anche se SELECT compare all'inizio dell'istruzione, logicamente non è la prima parte a essere elaborata. L'ordine reale con cui SQL elabora i dati è il seguente:
FROM: per prima cosa viene individuata la tabella, o le tabelle, da cui recuperare i dati.WHERE: vengono filtrate le singole righe.GROUP BY: le righe rimaste vengono suddivise in gruppi.HAVING: vengono filtrati i gruppi e mantenuti soltanto quelli che soddisfano la condizione.SELECT: vengono determinati i valori da restituire.DISTINCT: se è presente, vengono eliminati eventuali risultati duplicati.ORDER BY: i risultati vengono ordinati secondo i criteri specificati.LIMIT: infine viene applicato il limite al numero di risultati.