🗃️ GROUP BY e HAVING

Guida completa con l'approccio delle "sottotabelle"

📊 1. La Tabella di Partenza

Per tutti gli esempi useremo questa tabella vendite (ampliata per mostrare casi complessi):

🗄️ Tabella: vendite
id venditore categoria prodotto importo quantita
1MarioElettronicaSmartphone599.002
2LuigiAbbigliamentoGiacca89.003
3MarioElettronicaTablet450.001
4AnnaAbbigliamentoScarpe120.002
5LuigiElettronicaCuffie79.005
6MarioCasaLampada45.004
7AnnaElettronicaMouse25.0010
8LuigiCasaCuscino35.006
9MarioAbbigliamentoMaglietta29.008
10AnnaCasaVaso55.003
11LuigiElettronicaTastiera65.002
12MarioElettronicaMonitor299.001
13MarioCasaTappeto120.001
14MarioCasaQuadro80.002
15MarioAbbigliamentoCintura40.005
16LuigiAbbigliamentoSciarpa25.002
17LuigiAbbigliamentoGuanti30.001
18LuigiCasaSedia150.004

📦 2. GROUP BY - Dividere la Tabella in Sottotabelle

🎯 L'IDEA CHIAVE

GROUP BY divide la tabella originale in tante SOTTOTABELLE,
una per ogni valore diverso della colonna specificata.

Poi esegue i calcoli (SUM, COUNT, AVG, ecc.) separatamente su ogni sottotabella.

Visualizziamo il Concetto

Quando scriviamo GROUP BY venditore, SQL prende la tabella e la "spezza" in sottotabelle:

👤 Sottotabella MARIO
venditoreimporto
Mario599.00
Mario450.00
Mario45.00
Mario29.00
Mario299.00
Mario120.00
Mario80.00
Mario40.00
👤 Sottotabella LUIGI
venditoreimporto
Luigi89.00
Luigi79.00
Luigi35.00
Luigi65.00
Luigi25.00
Luigi30.00
Luigi150.00
👤 Sottotabella ANNA
venditoreimporto
Anna120.00
Anna25.00
Anna55.00
⬇️
Una riga per ogni sottotabella
⬇️

📤 Risultato Finale:

venditore totale num_vendite
Mario1662.008
Luigi473.007
Anna200.003

🔍 3. Esempi Pratici di GROUP BY

Esempio 1: Raggruppamento per Categoria

Domanda: "Quanto abbiamo venduto per ogni categoria?"

SELECT categoria, SUM(importo) AS totale, COUNT(*) AS num_vendite FROM vendite GROUP BY categoria;

📤 Risultato:

categoria totale num_vendite
Elettronica1517.006
Abbigliamento333.006
Casa485.006

Esempio 2: GROUP BY su Due Colonne

Domanda: "Quanto ha venduto ogni venditore in ogni categoria?"

Qui le cose si fanno interessanti. Noi dobbiamo dividere la tabella in sottotabelle, una per ogni venditore e dopodichè ogni sottotabella va divisa in gruppi di righe, una per ogni categoria. E questo si ottiene con GROUP BY Venditore, Categoria

Per visualizzarlo facilmente: immagina di avere una tabella per ogni venditore (Mario, Luigi, Anna) e, dentro questa tabella, le vendite vengono suddivise per colore in base alla categoria.

SELECT venditore, categoria, SUM(importo) AS totale FROM vendite GROUP BY venditore, categoria ORDER BY venditore, categoria;

📦 Sottotabelle per Venditore (le righe sono colorate per Categoria):

Ogni blocco di colore uniforme verrà collassato in UNA sola riga nel risultato.

⚡ Elettronica
👕 Abbigliamento
🏠 Casa
👤 Sottotabella MARIO
ProdottoImporto
Smartphone599.00
Tablet450.00
Monitor299.00
Maglietta29.00
Cintura40.00
Lampada45.00
Tappeto120.00
Quadro80.00
👤 Sottotabella LUIGI
ProdottoImporto
Cuffie79.00
Tastiera65.00
Giacca89.00
Sciarpa25.00
Guanti30.00
Cuscino35.00
Sedia150.00

📤 Risultato Finale:

venditore categoria totale
AnnaAbbigliamento120.00
AnnaCasa55.00
AnnaElettronica25.00
LuigiAbbigliamento144.00
LuigiCasa185.00
LuigiElettronica144.00
MarioAbbigliamento69.00
MarioCasa245.00
MarioElettronica1348.00

🎯 4. HAVING - Selezionare Solo Alcune Sottotabelle

🎯 L'IDEA CHIAVE

HAVING è una condizione che FILTRA le sottotabelle.

Dopo che GROUP BY ha creato le sottotabelle e calcolato i risultati,
HAVING decide quali sottotabelle includere nel risultato finale
e quali escludere.

Esempio Visivo

Domanda: "Mostrami solo i venditori che hanno venduto più di 1000€ in totale"

SELECT venditore, SUM(importo) AS totale FROM vendite GROUP BY venditore HAVING SUM(importo) > 1000;

Passo 1: GROUP BY crea le sottotabelle -- Se sposti il mouse sul rettangolo "ESCLUSA" vedrai i calcoli che hanno escluso la sottotabella

👤 MARIO
👤 LUIGI
👤 ANNA

📤 Risultato (solo sottotabelle che passano il filtro):

venditore totale
Mario1662.00

Solo la sottotabella di Mario ha superato la condizione HAVING!

⚖️ 5. WHERE vs HAVING - La Differenza

WHERE

Filtra le RIGHE
prima di creare le sottotabelle

  • Agisce sulla tabella originale
  • Decide quali righe entrano nelle sottotabelle
  • NON può usare funzioni aggregate

HAVING

Filtra le SOTTOTABELLE
dopo averle create

  • Agisce sui gruppi già formati
  • Decide quali sottotabelle includere nel risultato
  • PUÒ usare funzioni aggregate

Esempio Pratico: WHERE + HAVING insieme

Domanda: "Per le vendite sopra i 50€, mostrami i venditori con almeno 2 vendite"

SELECT venditore, COUNT(*) AS vendite, SUM(importo) AS totale FROM vendite WHERE importo > 50 -- Filtra RIGHE prima del grouping GROUP BY venditore HAVING COUNT(*) >= 2; -- Filtra SOTTOTABELLE dopo il grouping
1
WHERE importo > 50

Prima vengono escluse le righe con importo ≤ 50.

2
GROUP BY venditore

Le righe rimanenti vengono divise in sottotabelle per venditore.

3
HAVING COUNT(*) >= 2

Vengono incluse solo le sottotabelle con almeno 2 righe valide.

📤 Risultato:

venditore vendite totale
Mario51593.00
Luigi4383.00
Anna2175.00

🔄 6. Ordine: Scrittura vs Esecuzione

Spesso si fa confusione perché l'ordine in cui SCRIVI i comandi è diverso dall'ordine in cui SQL li ESEGUE.

✍️ SINTASSI
(Come lo scrivi)
SELECT
FROM
WHERE
GROUP BY
HAVING
ORDER BY
⚙️ LOGICA
(Come viene eseguito)
FROM
WHERE
GROUP BY
HAVING
SELECT
ORDER BY

🧐 Il Paradosso del SELECT

Hai notato? Anche se SELECT è la prima parola che scrivi, logicamente è la quinta operazione eseguita!

Ecco perché SELECT è quasi alla fine: il database deve prima trovare i dati (FROM), filtrarli (WHERE), raggrupparli (GROUP BY) e filtrare i gruppi (HAVING). Solo a quel punto decide quali colonne mostrarti e calcola i risultati finali.

E infine, solo dopo aver "selezionato" i dati finali, può ordinarli (ORDER BY).

📋 Esempio: Ordine di Scrittura vs Esecuzione

SELECT categoria, SUM(importo)
Esegue per 5° Calcola i valori da mostrare
FROM vendite
Esegue per 1° Trova la tabella
WHERE quantita > 1
Esegue per 2° Filtra le righe inutili
GROUP BY categoria
Esegue per 3° Crea le sottotabelle
HAVING SUM(importo) > 1000
Esegue per 4° Filtra le sottotabelle
ORDER BY totale DESC
Esegue per 6° Ordina il risultato finale
LIMIT 5;
Esegue per 7° Taglia le righe in eccesso

🎯 7. Esempi Completi

Esempio 1: Report Venditori

Domanda: "Mostra i venditori con più di 250€ venduti, ordinati dal migliore"

SELECT venditore, COUNT(*) AS vendite, SUM(importo) AS totale, ROUND(AVG(importo), 2) AS media FROM vendite GROUP BY venditore HAVING SUM(importo) > 250 ORDER BY totale DESC;

📤 Risultato:

venditore vendite totale media
Mario81662.00207.75
Luigi7473.0067.57

Esempio 2: Combinazioni Venditore-Categoria

Domanda: "Trova le combinazioni venditore+categoria con totale > 100€"

SELECT venditore, categoria, SUM(importo) AS totale, SUM(quantita) AS pezzi FROM vendite GROUP BY venditore, categoria HAVING SUM(importo) > 100 ORDER BY totale DESC;

📤 Risultato:

venditore categoria totale pezzi
MarioElettronica1348.004
MarioCasa245.007
LuigiCasa185.0010
LuigiAbbigliamento144.006
LuigiElettronica144.007
AnnaAbbigliamento120.002

⚠️ 8. Errori Comuni da Evitare

Errore 1: Colonne non aggregate nel SELECT

❌ SBAGLIATO

SELECT venditore, prodotto, -- ❌ Errore! SUM(importo) FROM vendite GROUP BY venditore;

"prodotto" non è nel GROUP BY. In una sottotabella di Mario ci sono 8 prodotti diversi: quale mostrare?

SELECT venditore, SUM(quantita) AS pezzi FROM vendite GROUP BY venditore HAVING SUM(quantita) > 15;

Nel SELECT Solo colonne del GROUP BY o funzioni aggregate

📝 9. Esercizi

Esercizio 1 - Base

Conta quante vendite sono state fatte per ogni categoria.

Mostra Soluzione
SELECT categoria, COUNT(*) AS num_vendite FROM vendite GROUP BY categoria;

Esercizio 2 - HAVING

Trova i venditori che hanno venduto più di 15 pezzi totali.

Mostra Soluzione
SELECT venditore, SUM(quantita) AS pezzi FROM vendite GROUP BY venditore HAVING SUM(quantita) > 15;

Esercizio 3 - WHERE + HAVING

Per le vendite di importo superiore a 40€, trova le categorie con almeno 2 vendite.

Mostra Soluzione
SELECT categoria, COUNT(*) AS vendite FROM vendite WHERE importo > 40 GROUP BY categoria HAVING COUNT(*) >= 2;

Esercizio 4 - Avanzato

Trova le combinazioni venditore+categoria dove la media per vendita supera la media generale.

Mostra Soluzione
SELECT venditore, categoria, AVG(importo) AS media FROM vendite GROUP BY venditore, categoria HAVING AVG(importo) > (SELECT AVG(importo) FROM vendite);

📌 Riepilogo Finale

GROUP BY

Divide la tabella in SOTTOTABELLE
(una per ogni valore unico della colonna)
e calcola le funzioni aggregate su ciascuna

HAVING

Filtra le SOTTOTABELLE
Include nel risultato solo le sottotabelle
che soddisfano la condizione specificata

Schema Mentale

-- 1. WHERE filtra le RIGHE della tabella originale

-- 2. GROUP BY crea le SOTTOTABELLE

-- 3. HAVING decide quali SOTTOTABELLE tenere