18th Jul 2022 Tempo di lettura: 13 minuti 7 errori comuni di GROUP BY Marija Ilic sql imparare sql GROUP BY Indice Smettete di commettere questi 7 errori comuni di GROUP BY 1. Dimenticare GROUP BY con le funzioni aggregate 2. Confondere WHERE e HAVING Esempio 1 - Come visualizzare le categorie dei pasti con più di 1M di visualizzazioni Esempio 2 - Prestazioni di John in ogni categoria di pasti 3. Elencare una colonna in SELECT ma non in GROUP BY 4. Non raggruppare per una chiave univoca 5. Confondere COUNT(distinct) e COUNT(*) 6. Problemi nell'uso di funzioni aggregate con NULL 7. Utilizzo di COUNT(*) con GROUP BY e una LEFT JOIN È possibile risolvere gli errori GROUP BY! State commettendo questi errori con la clausola GROUP BY in SQL? Scoprite quali sono, come evitarli e come risolverli. L'istruzione GROUP BY di SQL può svelare rapidamente potenti informazioni sui dati. All'inizio, l'uso di GROUP BY può sembrare semplice, ad esempio per la creazione di report SQL di base da presentare ai responsabili delle decisioni aziendali. Ma mentre si impara questa potente funzione, si rischia di rimanere intrappolati in strani errori o di ottenere risultati errati causati da istruzioni GROUP BY scritte in modo improprio. Se vi sembra che i conti non tornino con l'uso di GROUP BY, continuate a leggere. In questo articolo spiegherò gli errori più comuni di GROUP BY e come evitarli. Smettete di commettere questi 7 errori comuni di GROUP BY 1. Dimenticare GROUP BY con le funzioni aggregate Si utilizzano le istruzioni di SELECT con la clausola GROUP BY quando si desidera raggruppare e organizzare le righe in gruppi specifici ed eseguire quindi un calcolo specifico per ciascun gruppo. L'errore GROUP BY più comune è dimenticare di scrivere GROUP BY all'interno dell'istruzione SELECT. Ecco un esempio. Immaginiamo di avere una tabella ricetteche contiene 100 record e sei colonne. Questa tabella memorizza il numero di visualizzazioni (no_of_views) per ogni ricetta pubblicata su un famoso sito web culinario: meal_categorynameauthorno_of_viewsno_of_views_lst_mthauthor_id Cold appetizerMarinated CheeseMarta107104906211 SoupsPumpkin soupJohn68856693772 dessertsBanana CheesecakeAlly131944NULL3 drinksPaloma PicanteLuke72027713124 Bread and pastrySour Cream DoughnutsJohn50935527912 dessertsReal Strawberry CupcakesLisa17626811693911 Soupspotato soupMary64796643886 .................. .................. .................. Bread and pastryCider DoughnutsTim53896511608 tabella delle ricette Ecco una breve descrizione delle colonne della tabella: meal_category - La categoria della ricetta (zuppa, bevande, dessert, ecc.). name - Il nome della ricetta. author - Il nome dell'autore. no_of_views - Il numero di visualizzazioni (totale pagine/ricette visualizzate) nel mese corrente. no_of_views_lst_mth - Il numero di visualizzazioni (totale pagine/ricette visualizzate) nel mese precedente. author_id - Il numero ID univoco dell'autore. Supponiamo di voler contare il numero di ricette in ogni categoria di pasti. Se si scrive l'istruzione in questo modo (senza GROUP BY alla fine)... SELECT meal_category, count(*) AS total_recipes FROM recipes ; ... la maggior parte dei motori SQL darà un errore. Alcuni motori, tuttavia, daranno risultati strani e indesiderati. Sto usando MySQL e quando eseguo questa istruzione, ottengo questo: meal_categorytotal_recipes Cold appetizer100 Risultato senza GROUP BY 100 è il conteggio totale di tutte le ricette dell'intero set di dati e la categoria "antipasto freddo" è solo una categoria su dieci. Per correggere questo tipo di errore, è necessario aggiungere un GROUP BY meal_category alla fine dell'istruzione. (Altrimenti, il risultato in MySQL non ha senso). La SELECT corretta si presenta in questo modo: SELECT meal_category, count(*) AS total_recipes FROM recipes GROUP BY meal_category ; Ecco una breve spiegazione di ciò che sta accadendo: I record vengono uniti in base alla categoria del pasto. Per esempio, i dessert sono un gruppo, le zuppe un altro, i piatti principali un altro ancora, ecc. La colonna meal_category è specificata dopo GROUP BY; è anche elencata in SELECT. Per ogni gruppo, utilizziamo COUNT(*) per contare il numero totale di ricette in quel gruppo. Non mi addentrerò nella sintassi, ma vi suggerisco di leggere GROUP BY in SQL Explained o Using GROUP BY in SQL per maggiori dettagli. Come si può vedere, il risultato è quello atteso: meal_categorytotal_recipes Bread and pastry7 Cold appetizer6 desserts20 drinks7 Main dishes20 Salads8 Side dishes12 Soups17 Warm appetizer3 Risultato valido di GROUP BY 2. Confondere WHERE e HAVING Forse si desidera visualizzare solo le categorie di pasti che hanno più di 10 ricette. Molti principianti scriverebbero questa query: SELECT meal_category, count(*) AS total_recipes FROM recipes WHERE count(*) > 10 GROUP BY meal_category ; Questa istruzione restituirà un errore perché non è possibile utilizzare funzioni aggregate in una clausola WHERE. WHERE si utilizza con GROUP BY quando si desidera filtrare le righe prima di raggrupparle. Nel nostro esempio, vogliamo filtrare le righe dopo il raggruppamento; in casi come questo, dobbiamo utilizzare la clausola HAVING: SELECT meal_category, count(*) AS total_recipes FROM recipes GROUP BY meal_category HAVING count(*) > 10 ; Questo fraintendimento sulla differenza tra HAVING e WHERE è il secondo errore più comune con GROUP BY. Chiariamo questa differenza con altri due esempi. Esempio 1 - Come visualizzare le categorie dei pasti con più di 1M di visualizzazioni Un'istruzione che visualizzi solo le categorie con più di 1 milione di visualizzazioni totali di pagina può essere scritta in questo modo: SELECT meal_category, sum(no_of_views) AS total FROM recipes GROUP BY meal_category HAVING sum(no_of_views) >1000000; In questo caso utilizziamo HAVING perché vogliamo filtrare i record dopo che sono stati raggruppati. Il risultato è presentato di seguito: meal_categorytotal desserts2969324 Main dishes1323981 Side dishes1662910 Soups1100911 Esempio con HAVING Esempio 2 - Prestazioni di John in ogni categoria di pasti Questa query estrae solo le ricette di John e calcola le sue prestazioni: SELECT meal_category, sum(no_of_views) AS total FROM recipes WHERE author = ‘John’ GROUP BY meal_category; Usiamo WHERE perché dobbiamo filtrare i record (in modo da ottenere solo i dati di John) prima di mettere i record in gruppi per categoria di pasto. Ecco come appare il risultato: meal_categorytotal Bread and pastry50935 desserts301869 drinks147745 Main dishes279934 Salads88097 Side dishes415864 Soups393253 Warm appetizer85570 I KPI di John HAVING e WHERE sono ben descritti nei nostri articoli Qual è la differenza tra le clausole WHERE e HAVING in SQL? e 5 esempi di GROUP BY. Se volete vedere altri esempi su questo argomento, vi suggerisco di iniziare da lì. 3. Elencare una colonna in SELECT ma non in GROUP BY Supponiamo di voler vedere il numero totale di visualizzazioni per meal_category e author. Possiamo farlo, basta aggiungere la colonna autore alla nostra query precedente: SELECT meal_category, author, sum(no_of_views) AS total FROM recipes GROUP BY meal_category; Certo che no: nella maggior parte dei motori SQL si verificherà un errore. Per esempio, Oracle vi dirà "errore: Non è un'espressione GROUP BY". Perché questo errore di confusione? Cosa manca qui? Il motore SQL non sa come calcolare il totale per ogni autore perché non lo abbiamo incluso nella clausola GROUP BY; l'attributo author non è elencato nella clausola GROUP BY. Questo è un altro errore comune con i GROUP BY. Correggiamo la query ed eseguiamola ancora una volta: SELECT meal_category, author, sum(no_of_views) AS total FROM recipes GROUP BY meal_category, author; Il risultato è: meal_categoryauthortotal Bread and pastryDino53789 Bread and pastryJohn50935 Bread and pastryMarta52998 Bread and pastryMary52904 Bread and pastryPatricia51451 Bread and pastryTim106226 ......... ......... ......... SoupsMary125731 SoupsMonte128356 SoupsPatricia255574 SoupsTim132532 Warm appetizerJohn85570 Warm appetizerLisa82960 Warm appetizerMary87560 Ora sembra tutto a posto. Ricordate che le colonne non aggregate elencate in SELECT devono essere elencate anche in .GROUP BYNel nostro caso, le colonne non aggregate sono meal_category e author, che ora si trovano in SELECT e GROUP BY. Non si elencano le colonne che si trovano all'interno di funzioni aggregate in GROUP BY. Nel nostro esempio, la colonna no_of_views è usata nella funzione aggregata SUM() e quindi non è elencata nella clausola GROUP BY. Per ulteriori informazioni su questo argomento, consultare l'articolo Clausola GROUP BY: Quanto la conoscete? Spiega perché le colonne selezionate devono comparire nella clausola GROUP BY. Inoltre, Come risolvere un errore "Non è un'espressione GROUP BY" fornisce altri esempi relativi a questo tipo di errore. 4. Non raggruppare per una chiave univoca Ora proviamo un'altra cosa. Supponiamo di voler ottenere il numero medio di pagine viste per ogni autore di ricette. La seguente query calcola il numero medio totale di pagine viste per ogni autore utilizzando il nome dell'autore: SELECT author, avg(no_of_views) FROM recipes GROUP BY author; Osservando il risultato, si noterà che Lisa ha una media di 116101,5 pagine viste: authoravg(NO_OF_VIEWS) Ally106545 Dino94667.9091 John88163.35 Lisa116101.5 Luke104591 Marta119789.1667 Mary101040.0588 Monte84794 Patricia81911.1333 Tim76185.375 GROUP BY author - ma i nomi non sono unici Tuttavia, nella nostra tabella abbiamo due autori di nome Lisa. Quando raggruppiamo i risultati in base alla colonna autore, entrambe le Lisa vengono valutate insieme. Perché? Perché stiamo usando una colonna non univoca in GROUP BY. Ciò significa che non tutti i valori del raggruppamento devono essere univoci. Se vogliamo vedere la media di ogni Lisa separatamente, dobbiamo aggiungere author_id (una colonna univoca) all'elenco GROUP BY: SELECT author, author_id avg(no_of_views) FROM recipes GROUP BY author, author_id; Ora vediamo come le ricette di Lisa(id=11) siano molto più viste delle ricette di Lisa(id=5): authorauthor_idavg(no_of_views) Ally3106545 Dino794667.9091 John288163.35 Lisa585798 Lisa11146405 Luke4104591 Marta1119789.1667 Mary6101040.0588 Monte984794 Patricia1081911.1333 Tim876185.375 GROUP BY con autore e author_id È importante pensare sempre alle chiavi di raggruppamento. I valori di raggruppamento devono essere unici e devono rappresentare ogni gruppo nel modo desiderato. Altrimenti, si otterranno risultati imprecisi e confusi e forse un errore GROUP BY. 5. Confondere COUNT(distinct) e COUNT(*) Se siete curiosi di vedere il numero totale di autori per ogni categoria di pasto, potete scrivere un'istruzione GROUP BY per calcolarlo. Utilizziamo COUNT(*) e recuperiamo il numero di autori per ogni categoria: SELECT meal_category, count(*) FROM recipes GROUP BY meal_category; Ecco il risultato, ma non è quello che vi aspettavate, vero? meal_categorycount(*) Bread and pastry7 Cold appetizer6 desserts20 drinks7 Main dishes20 Salads8 Side dishes12 Soups17 Warm appetizer3 Si tratta del numero totale di ricette in ogni categoria, non del numero totale di autori. Perché? Perché COUNT(*) conta tutte le righe di ogni gruppo. La tabella ricette contiene informazioni a recipe livello: ogni record è una ricetta. Questa query conta le ricette (righe) in ogni categoria, non gli autori delle ricette. Un autore può avere molte ricette in ogni categoria, quindi per ottenere le informazioni desiderate è necessario contare gli autori distinti (usando COUNT(distinct author) invece di COUNT(*)) all'interno di ogni gruppo. Questo è un errore molto comune di GROUP BY. Quindi, quando si dovrebbero usare COUNT(*), COUNT(expression) e COUNT(distinct expression)? Vediamo un esempio: SELECT meal_category, count(distinct author), count(author), count(*) FROM recipes GROUP BY meal_category; meal_categorycount(distinct author)count(author)count(*) Bread and pastry677 Cold appetizer266 desserts82020 drinks577 Main dishes92020 Salads688 Side dishes81212 Soups61717 Warm appetizer333 La differenza tra COUNT(*) e COUNT(expression) è visibile se si eseguono calcoli su una colonna con alcuni valori mancanti. In presenza di valori mancanti, COUNT(*) conterà tutti i record di un gruppo, mentre COUNT(expression) conterà solo i valori non nulli. Nell'esempio precedente, COUNT(*) e COUNT(author) danno lo stesso risultato perché la colonna autore non ha valori NULL. COUNT(distinct author) fornisce il numero di autori distinti per ogni categoria, che non è lo stesso di COUNT(*). Ad esempio, la categoria antipasto freddo contiene sei ricette di due autori distinti. COUNT(*) conta il numero di ricette (record) in ogni categoria, mentre COUNT(distinct author) conta il numero di autori distinti. Quindi, se si desidera visualizzare il numero totale di autori distinti per ogni categoria di pasto, utilizzare COUNT(distinct author). Ecco la query corretta: SELECT meal_category, count(distinct author) FROM recipes GROUP BY meal_category; GROUP BY meal_category; Per una spiegazione più dettagliata, vedere Qual è la differenza tra COUNT(*), COUNT(1), COUNT(nome colonna) e COUNT(nome colonna DISTINCT)? 6. Problemi nell'uso di funzioni aggregate con NULL Questo è un altro problema di "valore mancante". Supponiamo di voler calcolare il numero totale medio di visualizzazioni del mese precedente per ogni categoria. Il vostro collega ha calcolato queste cifre, ma vorrebbe che voi verificaste il risultato. Ecco la vostra domanda: SELECT meal_category, avg(no_of_views_lst_mth) as average, FROM recipes GROUP BY meal_category; E ciò che si ottiene è... meal_categoryaverage Bread and pastry52274.8571 Cold appetizer95584.2 desserts144349.7222 drinks72551.7143 Main dishes61350.8889 Salads90798.875 Side dishes139765.25 Soups64978.8824 Warm appetizer78390.6667 Il risultato sembra corretto e siete sicuri della correttezza della vostra domanda. Tuttavia, il vostro collega ha ottenuto cifre leggermente diverse: meal_categoryaverage Bread and pastry52274.8571 Cold appetizer79653.5 desserts129914.75 drinks72551.7143 Main dishes55215.8 Salads90798.875 Side dishes139765.25 Soups64978.8824 Warm appetizer78390.6667 Cosa è successo? Perché questi risultati diversi? In poche parole, i risultati diversi derivano da interpretazioni diverse dei valori mancanti. La colonna no_of_views_lst_mth rappresenta il numero di pagine viste totali nel mese precedente. Se una ricetta è stata creata nel mese corrente, questa colonna sarà nulla per quella riga. Ad esempio, la ricetta Banana Cheesecake di Ally è stata scritta nel mese corrente, quindi non ci sono statistiche per il mese precedente: meal_categorynameauthorno_of_viewsno_of_views_lst_mthauthor_id dessertsBanana CheesecakeAlly131944NULL3 La cheesecake alla banana è stata pubblicata nel mese corrente. Torniamo ora alle medie e ai loro diversi risultati. Le medie sono calcolate come la somma totale di no_of_views_lst_mth divisa per il numero totale di record. Se si utilizza la funzione AVG() e sono presenti dei NULL, il motore ignora i NULL ed esegue i calcoli senza di essi. Questo è ciò che è successo quando è stata eseguita la query: i NULL sono stati omessi. In alcuni casi, è necessario sostituire i NULL con 0 (perché lo impone la logica aziendale); questo è ciò che ha fatto il collega, che ha prodotto cifre leggermente diverse. Ecco la query del collega: SELECT meal_category, avg(CASE WHEN no_of_views_lst_mth is null THEN 0 ELSE no_of_views_lst_mth END) AS average FROM recipes GROUP BY meal_category; Si noti come le medie di queste due query trattino i NULL in modo diverso. Ad esempio, la categoria "dessert" contiene dei NULL. Pertanto, la prima query omette queste righe e non le conta per il numero totale di righe; si ottiene così il valore 144349,72. La seconda query sostituisce tutti i NULL con zero e conta queste righe nella media, ottenendo un valore inferiore di 129914,75. Direi che entrambe le query possono essere valide, a seconda di come si desidera calcolare le medie. 7. Utilizzo di COUNT(*) con GROUP BY e una LEFT JOIN L'uso di GROUP BY con un'istruzione LEFT JOIN può creare molta confusione, soprattutto con COUNT(). Vediamo come funzionano COUNT(*) e COUNT(expression) in una LEFT JOIN. Supponiamo che qualcuno del marketing abbia la seguente tabella, recipes_campaigns. Essa contiene informazioni sul numero di campagne eseguite su ciascuna categoria di pasti nel mese corrente: meal_categorycampaigns Bread and pastry2 Cold appetizer1 desserts3 drinks0 Main dishes3 Salads1 Side dishes2 Soups3 Warm appetizer0 brunch1 sandwiches0 ricette_campagna Oltre ai dati contenuti in recipes_campaignsl'addetto al marketing vuole anche vedere il numero di ricette per ogni categoria di pasto. A tal fine, sono necessarie le informazioni della tabella recipes tabella. Quindi uniamo le due tabelle e calcoliamo il numero di ricette utilizzando COUNT(*), in questo modo: SELECT a.meal_category, count(*), FROM recipes_campaigns a LEFT JOIN recipes b ON a.meal_category=b.meal_category GROUP BY a.meal_category; Ecco il risultato: meal_categorycount(*) Bread and pastry7 brunch1 Cold appetizer6 desserts20 drinks7 Main dishes20 Salads8 sandwiches1 Side dishes12 Soups17 Warm appetizer3 Non è quello che ci aspettavamo. La tabella recipe non contiene ricette nella categoria "brunch", quindi perché abbiamo ottenuto quell'1 nel risultato? Questo accade perché COUNT() viene applicato al risultato di LEFT JOIN! Quando si LEFT JOIN due tabelle, la categoria "brunch" sarà presente nel risultato, anche se nella tabella non ci sono ricette o categorie corrispondenti. recipe tabella. Come possiamo risolvere questo problema? Se usiamo COUNT(expression) invece di COUNT(*), otterremo il risultato desiderato: SELECT a.meal_category, count(author_id), FROM recipes_campaigns a LEFT JOIN recipes b ON a.meal_category=b.meal_category GROUP BY a.meal_category; Una volta eseguito, si ottiene: meal_categorycount(author_id) Bread and pastry7 brunch0 Cold appetizer6 desserts20 drinks7 Main dishes20 Salads8 sandwiches0 Side dishes12 Soups17 Warm appetizer3 Qui, COUNT(author_id) conta solo i valori non NULL in author_id dopo che è stato eseguito LEFT JOIN. Non c'è alcun valore in author_id per la categoria "brunch"; in altre parole, è NULL e il risultato per quella categoria è 0. È possibile risolvere gli errori GROUP BY! Attraverso diversi esempi, abbiamo esplorato il GROUP BY e gli errori più comuni che i principianti spesso commettono. Spero che ora abbiate un'idea più chiara di come funziona GROUP BY e di cosa causa quegli strani errori o risultati confusi. GROUP BY è davvero molto importante nella creazione dei report. Se volete imparare a costruire dei buoni report, vi consiglio il nostro Creating Basic SQL Reports corso. Contiene molti esercizi interattivi che consentono di acquisire esperienza nella scrittura di query GROUP BY per i report. E una maggiore esperienza riduce certamente la possibilità di errori! Tags: sql imparare sql GROUP BY