Raggruppare con GROUP BY e filtrare con HAVING
Gli argomenti di questa pagina
|
Le clausole GROUP BY e HAVING
Con le query SQL è possibile combinare la sintassi "GROUP BY" con "HAVING" per filtrare ulteriormente i risultati di valori aggregati.
La clausola HAVING specifica ulteriori filtri che vengono applicati dopo i filtri della clausola WHERE.
La condizione di ricerca specificata nella clausola WHERE viene applicata prima dell'operazione di raggruppamento eseguita tramite la clausola GROUP BY, mentre la condizione di ricerca della clausola HAVING viene applicata dopo tale operazione.
La differenza tra le clausole WHERE ed HAVING fondamentalmente sono queste:
con la clausola WHERE si applica la condizione di ogni singola riga.
con la clausola HAVING si applica la condizione di ciascun gruppo di righe ottenute tramite la clausola GROUP BY.
Quando si utilizza con la clausola GROUP BY, è possibile applicare una condizione di filtro per le colonne che appaiono nella clausola GROUP BY.
Se la clausola GROUP BY viene omessa si comporta come la clausola WHERE.
Inizialmente è possiblie rimanere confusi circa la differenza tra il WHERE e HAVING. In fondo con esse si esprimono le stesse condizioni ed anno anche un aspetto sintattico simile.
In pratica:
- nella clausola SELECT vengono selezionati i campi da visualizzare
- la clausola FROM definisce la tabella o le tabelle da cui prelevare i dati
- tramite la clausola WHERE vengono filtrati i record da accettare secondo i criteri espressi
- con la clausola GROUP BY, i record accettati vengono raggruppati e aggregati
- la clausola HAVING consente di applicare un ulteriore filtro sui record restituiti dopo il raggruppamento
In questa pagina viene esaminato il modo di restituire le righe in base a un criterio utilizzando HAVING come criterio per l'ulteriore filtro.
Le tabelle usate in questa pagina
Prima di iniziare coi nostri esempi vediamo alcune righe delle tabelle su cui andremo a lavorare
Le due tabelle Per la tabella sql_libri: 22 record trovati 15 record visualizzati
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Per la tabella sql_rubrica: 101 record trovati 15 record visualizzati
|
Codice per eseguire le Query
Tutte le Query presentate come esempi sono eseguibili tramite questo script.
1
|
<?php
|
Esempi di Query con la sola clausola GROUP BY
Per ogni esempio mostriamo la richiesta che si fa tramite la Query.
Con questo esempio viene cercato il prezzo maggiore tra i libri di ciascun gruppo senza applicare alcun filtro.
Mostra il prezzo più alto dei libri appartenenti a ciascun gruppo
esempio 1
|
5 record trovati 5 record visualizzati
|
Questo secondo esempio è simile a quello precedente, ma viene scelta la tabella sql_rubrica e, per ciascuna città vengono contate tutte le occorrenze.
Il count con l'asterisco tra parentesi fa riferimento ai campi indicati nella clausola group by.
La seguente query, anche questa senza alcun filtro, pone la seguente richiesta:
Mostra i cap, le città e provinve e il numero delle occorrenze delle città
esempio 1 a
|
18 record trovati 15 record visualizzati
|
Questo esempio è simile al precedente, ma non esegue il raggruppamento sul solo campo città, ma anche sul campo CAP.
Per questo motivo il resultset restituito è più lungo del precedente.
La Query pone questo quesito:
Mostra i cap, le città e provinve e il numero delle coppie citta - province
esempio 1 b
|
22 record trovati 15 record visualizzati
|
Alcuni esempi con le clausole GROUP BY e HAVING
Cominciamo ad applicare un filtro sui gruppi.
Per applicare un filtro su dati raggruppati viene usata la clausola HAVING dopo il raggruppamento.
Cerca i prezzi massimi dei libri appartenenti a ciascun gruppo ma mostra solo quelli che hanno un prezzo maggiore o uguale a 260.00
esempio 2
|
3 record trovati 3 record visualizzati
|
Il problema è simile a quello precedente, ma viene usata la tabella sql_rubrica.
Per ogni provincia mostra quelle che hanno più di 9 città
esempio 3
|
5 record trovati 5 record visualizzati
|
La richiesta è opposta a quella precedente
Per ogni provincia mostra quelle che hanno meno 10 di città
esempio 4
|
17 record trovati 15 record visualizzati
|
Qui di seguito vengono mostrate tre Query simili tra loro.
Nella prima viene eseguito il raggruppamento sulla sola provincia
Nella seconda il raggruppamento viene eseguito sulla coppia città e provincia
La terza è simile alla seconda ma non viene eseguito alcun conteggio
Questa Query risponde alla domanda:
Mostra l'elenco delle città e quante città sono archiviate
esempio 5
|
14 record trovati 14 record visualizzati
|
In questo esempio il raggruppamento avviene su due campi: città e provincia.
Quindi questa Query risponde alla domanda:
Mostra l'elenco delle città, anche se di diverse province, e quante città sono archiviate
esempio 5 a
|
14 record trovati 14 record visualizzati
|
In questo esempio non viene eseguito nessun conteggio, ma il raggruppamento viene eseguito su città e provincia. La richiesta è la seguente:
Mostra l'elenco delle città e province in cui abitano i nostri contatti
esempio 5 b
|
14 record trovati 14 record visualizzati
|
In questo esempio non viene usato alcun filtro
Mostra il valore complessivo di tutti i libri per ciascun gruppo
esempio 6
|
5 record trovati 5 record visualizzati
|
Questo esempio è simile al precedente ma come condizione viene posto di trovare solo quei gruppi che abbiano un valore inferiore a 195000
Mostra il valore complessivo di tutti i libri per ciascun gruppo ma che abbiano un valore minore a 195000
esempio 7
|
2 record trovati 2 record visualizzati
|
Nell'esempio che segue vengono cercati tutti i dati statistici. La richiesta è:
Per ogni gruppo cerca il numeri dei libri, il loro valore massimo, il loro valore minimo, la media del loro prezzo, ed il loro totale
esempio 8
|
5 record trovati 5 record visualizzati
|
Uso delle clausole WHERE e HAVING
La clausola WHERE e la clausola HAVING sono simili ma:
- la clausola WHERE è applicabile a righe singole,
- la clausola HAVING è applicabile solo ai gruppi come insieme, ossia alle righe nel resultset di risultati che rappresentano i gruppi.
Una Query può contenere sia una clausola WHERE che una clausola HAVING ma con queste semplici regole:
- La clausola WHERE viene applicata prima alle singole righe nelle tabelle o negli oggetti con valori di tabella.
- Quindi solo le righe che soddisfano le condizioni della clausola WHERE vengono raggruppate.
- Solo dopo l'operazione di raggruppamento può essere applicata la clausola HAVING alle righe del resultset di risultati. Nell'output della query saranno visualizzati solo i gruppi che soddisfano le condizioni HAVING.
La clausola HAVING può essere applicata solo alle colonne presenti anche nella clausola GROUP BY o in una funzione di aggregazione.
Si usa WHERE per esprimere condizioni su semplici valori, mentre è necessario usare HAVING per esprimere condizioni su valori aggregati.
Quindi la clausola WHERE viene applicata prima di effettuare i raggruppamenti su cui agisce invece la preposizione HAVING. Per questo motivo nella clausola WHERE non si può usare un campo usato in uba funzione di aggregazione.
Quando viene eseguita la Query, vengono prima analizzi i record secondo i criteri della clausola WHERE, poi, con i record risultanti, crea i raggruppamenti con la clausola GROUP BY. A questo punto vengono applicati i criteri specificati nella clausola
HAVING.
In questo modo è possibile stabilire la prima condizione includendo la clausola WHERE che consente di eliminare i record non richiesti.
Per la seconda condizione è necessario utilizzare la clausola HAVING, in quanto la condizione si basa sui risultati del raggruppamento e del riepilogo dei dati.
Alla Query vista qui sopra vorremmo aggiungere un filtro per escludere i libri che appartengono al gruppo della Corel. Perciò proviamo a rispondere a questo quesito:
Per ogni gruppo cerca il numeri dei libri, il loro valore massimo, il loro valore minimo, la media del loro prezzo, ed il loro totale ma escludi quelli che hanno un prezzo superiore a 250.00 e che non appartengono al gruppo corel
Viene spontaneo pensare alla seguente Query che purtroppo è destinata a fallire restituendo un errore.
Anche se nella tabella esiste il campo prezzo non viene riconosciuto nella clausola HAVING perchè questo campo non viene elencato nella clausola SELECT della Query. E' questo un caso in cui è necessario ricorrere alla clausola WHERE come mostrato più in basso.
esempio 8 a Questa Query è errata ... restituisce un errore
|
Unknown column 'prezzo' in 'having clause' |
Ecco come modificare la Query appena vista.
esempio 8 b
|
2 record trovati 2 record visualizzati
|
Questo esempio lo abbiamo visto nell'esempio 1 b, ma qui includiamo un filtro doppio: uno sulla città ed uno sul numero totale.
Mostra i cap, le città e provinve e il numero delle coppie citta - province se la città è diversa da Giusvalla e se il numero delle coppie citta - province è maggiore di 1
esempio 9
|
11 record trovati 11 record visualizzati
|
Il seguente esempio mostra un modo alternativo per creare una Query per rispondere al quesito appena vista.
Il filtro è impostato in maniera differente: una delle condizioni è posta nella clausola WHERE ed una nella clausola HAVING.
esempio 9 a
|
11 record trovati 11 record visualizzati
|