7th Jul 2022 Lectura de 13 minutos 7 errores comunes de GROUP BY Marija Ilic SQL aprender SQL agrupar por Índice Deja de cometer estos 7 errores comunes de GROUP BY 1. Olvidar GROUP BY con funciones agregadas 2. Confundiendo WHERE y HAVING Ejemplo 1 - Cómo mostrar las categorías de comidas con más de 1M de vistas Ejemplo 2 - Rendimiento de Juan en cada categoría de comida 3. Listando una Columna dentro de SELECT pero no en GROUP BY 4. No agrupar por una clave única 5. Confundir COUNT(distinct) y COUNT(*) 6. Problemas al utilizar funciones agregadas con NULLs 7. Usando COUNT(*) con GROUP BY y un LEFT JOIN Puede resolver los errores de GROUP BY ¿Estás cometiendo estos errores con GROUP BY en SQL? Descubra cuáles son, cómo evitarlos y cómo solucionarlos. La sentencia GROUP BY de SQL puede revelar rápidamente una poderosa visión de los datos. Al principio, el uso de GROUP BY puede parecer sencillo, por ejemplo, al crear informes SQL básicos que se presentarán a los responsables de la toma de decisiones empresariales. Pero mientras aprende esta poderosa función, podría quedar atrapado en errores extraños u obtener resultados incorrectos causados por sentencias GROUP BY mal escritas. Si sientes que las cosas no cuadran con tu uso de GROUP BY, sigue leyendo. En este artículo, explicaré los errores más comunes de GROUP BY y cómo puede evitarlos. Deja de cometer estos 7 errores comunes de GROUP BY 1. Olvidar GROUP BY con funciones agregadas Usted utiliza las sentencias SELECT con la cláusula GROUP BY cuando desea agrupar y organizar las filas en grupos específicos y luego realizar un cálculo específico de cada grupo. El error más común de GROUP BY es olvidarse de escribir GROUP BY dentro de la sentencia SELECT. He aquí un ejemplo. Imagine que tiene la tabla recetasque contiene 100 registros y seis columnas. Esta tabla almacena el número de vistas (no_of_views) por cada receta publicada en un famoso sitio 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 tabla de recetas A continuación, una breve descripción de las columnas de la tabla: meal_category - La categoría de la receta (sopa, bebidas, postres, etc.). name - El nombre de la receta. author - El nombre del autor. no_of_views - El número de visualizaciones (total de páginas/recetas vistas) en el mes en curso. no_of_views_lst_mth - El número de visitas (total de páginas/recetas vistas) del mes anterior. author_id - El número de identificación único del autor. Digamos que quiere contar el número de recetas en cada categoría de comida. Si escribe la sentencia así (sin GROUP BY al final) ... SELECT meal_category, count(*) AS total_recipes FROM recipes ; ... la mayoría de los motores SQL le darán un error. Algunos motores, sin embargo, darán resultados extraños y no deseados. Estoy usando MySQL y cuando ejecuto esta sentencia, obtengo lo siguiente meal_categorytotal_recipes Cold appetizer100 Resultado sin GROUP BY 100 es el recuento total de todas las recetas del conjunto de datos y la categoría de comida "Aperitivo frío" es sólo una categoría de las diez. Para corregir este tipo de error, es necesario añadir un GROUP BY meal_category al final de la sentencia. (De lo contrario, su resultado en MySQL no tiene sentido). El SELECT correcto tiene este aspecto: SELECT meal_category, count(*) AS total_recipes FROM recipes GROUP BY meal_category ; He aquí una breve explicación de lo que ocurre: Los registros se combinan según la categoría de la comida. Por ejemplo, los postres son un grupo, las sopas otro, los platos principales otro, etc. La columna meal_category se especifica después de GROUP BY; también aparece en SELECT. Para cada grupo, utilizamos COUNT(*) para contar el número total de recetas en ese grupo. No voy a profundizar en la sintaxis aquí, pero definitivamente te sugiero que leas Explicación de GROUP BY en SQL o Uso de GROUP BY en SQL para más detalles. Como puedes ver, el resultado es el esperado: meal_categorytotal_recipes Bread and pastry7 Cold appetizer6 desserts20 drinks7 Main dishes20 Salads8 Side dishes12 Soups17 Warm appetizer3 Resultado válido de GROUP BY 2. Confundiendo WHERE y HAVING Tal vez quiera ver sólo las categorías de comidas que tienen más de 10 recetas. Muchos principiantes escribirían esta consulta: SELECT meal_category, count(*) AS total_recipes FROM recipes WHERE count(*) > 10 GROUP BY meal_category ; Esta sentencia devolverá un error porque no se pueden utilizar funciones agregadas en una cláusula WHERE. WHERE se utiliza con GROUP BY cuando se desea filtrar filas antes de agruparlas. En nuestro ejemplo, queremos filtrar filas después de agruparlas; en casos como éste, necesitamos utilizar la cláusula HAVING: SELECT meal_category, count(*) AS total_recipes FROM recipes GROUP BY meal_category HAVING count(*) > 10 ; Este malentendido sobre la diferencia entre HAVING y WHERE es el segundo error más común con GROUP BY. Vamos a aclarar esta diferencia con dos ejemplos más. Ejemplo 1 - Cómo mostrar las categorías de comidas con más de 1M de vistas Una sentencia que muestre sólo las categorías con más de 1 millón de visitas totales a la página puede escribirse así: SELECT meal_category, sum(no_of_views) AS total FROM recipes GROUP BY meal_category HAVING sum(no_of_views) >1000000; Aquí estamos usando HAVING porque queremos filtrar los registros después de haberlos agrupado. El resultado se presenta a continuación: meal_categorytotal desserts2969324 Main dishes1323981 Side dishes1662910 Soups1100911 Ejemplo con HAVING Ejemplo 2 - Rendimiento de Juan en cada categoría de comida Esta consulta extrae sólo las recetas de Juan y calcula su rendimiento: SELECT meal_category, sum(no_of_views) AS total FROM recipes WHERE author = ‘John’ GROUP BY meal_category; Estamos usando WHERE porque necesitamos filtrar los registros (para que sólo obtengamos los datos de Juan) antes de poner los registros en grupos por categoría de comidas. El resultado es el siguiente: meal_categorytotal Bread and pastry50935 desserts301869 drinks147745 Main dishes279934 Salads88097 Side dishes415864 Soups393253 Warm appetizer85570 Los KPI de John HAVING y WHERE están bien descritos en nuestros artículos ¿Cuál es la diferencia entre las cláusulas WHERE y HAVING en SQL? y 5 ejemplos de GROUP BY. Si quieres ver más ejemplos sobre este tema, te sugiero que empieces por ahí. 3. Listando una Columna dentro de SELECT pero no en GROUP BY Ahora suponga que quiere ver el número total de vistas por meal_category y author. Podemos hacerlo... sólo tenemos que añadir la columna autor a nuestra consulta anterior: SELECT meal_category, author, sum(no_of_views) AS total FROM recipes GROUP BY meal_category; ¿Le parece bien? Por supuesto que no; arrojará un error en la mayoría de los motores SQL. Por ejemplo, Oracle le dirá "error: No es una expresión GROUP BY". ¿Por qué este error tan confuso? ¿Qué falta aquí? Pues bien, el motor SQL no sabe cómo calcular el total de cada autor porque no lo hemos incluido en la cláusula GROUP BY; el atributo autor no aparece dentro de la cláusula GROUP BY. Este es otro error común con GROUP BY. Arreglemos esta consulta y ejecutémosla una vez más: SELECT meal_category, author, sum(no_of_views) AS total FROM recipes GROUP BY meal_category, author; El resultado es: 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 Ahora esto parece estar bien. Recuerde que las columnas no agregadas que aparecen en SELECT también deben aparecer en GROUP BYEn nuestro caso, las columnas no agregadas son meal_category y author, que ahora están en SELECT y GROUP BY. No se enumeran las columnas que están dentro de las funciones agregadas en GROUP BY. En nuestro ejemplo, la columna no_of_views se utiliza en la función agregada SUM() y, por lo tanto, no aparece en la cláusula GROUP BY. Si desea obtener más información sobre este tema, consulte nuestro artículo Cláusula GROUP BY: ¿Qué tan bien la conoce? En él se explica por qué las columnas seleccionadas deben aparecer en la cláusula GROUP BY. También, Cómo solucionar un error de 'No es una expresión GROUP BY ' da más ejemplos relacionados con este tipo de error. 4. No agrupar por una clave única Ahora vamos a intentar algo más. Supongamos que queremos obtener el promedio de páginas vistas de cada autor de recetas. La siguiente consulta calcula la media del número total de páginas vistas de cada autor utilizando el nombre del autor: SELECT author, avg(no_of_views) FROM recipes GROUP BY author; Al ver el resultado, se observa que Lisa tiene una media de 116101,5 páginas vistas: authoravg(NO_OF_VIEWS) Ally106545 Dino94667.9091 John88163.35 Lisa116101.5 Luke104591 Marta119789.1667 Mary101040.0588 Monte84794 Patricia81911.1333 Tim76185.375 GROUP BY autor - pero los nombres no son únicos Sin embargo, en realidad tenemos dos autores llamados Lisa en nuestra tabla. Cuando agrupamos los resultados por la columna de autor, las dos Lisas se promedian juntas. ¿Por qué? Porque estamos utilizando una columna no única en GROUP BY. Esto significa que no todos los valores de agrupación tienen que ser únicos. Si queremos ver la media de cada Lisa por separado, deberíamos añadir author_id (una columna única) a la lista GROUP BY: SELECT author, author_id avg(no_of_views) FROM recipes GROUP BY author, author_id; Ahora vemos cómo las recetas de Lisa(id=11) son mucho más vistas que las recetas de 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 author y author_id Es importante pensar siempre en las claves de agrupación. Los valores de agrupación deben ser únicos y deben representar a cada grupo de la forma deseada. De lo contrario, obtendrás resultados inexactos y confusos y posiblemente un error de GROUP BY. 5. Confundir COUNT(distinct) y COUNT(*) Si tiene curiosidad por ver el número total de autores de cada categoría de comida, puede escribir una sentencia GROUP BY para calcularlo. Utilicemos COUNT(*) y recuperemos el número de autores de cada categoría: SELECT meal_category, count(*) FROM recipes GROUP BY meal_category; Este es el resultado - pero no es lo que esperabas, ¿verdad? meal_categorycount(*) Bread and pastry7 Cold appetizer6 desserts20 drinks7 Main dishes20 Salads8 Side dishes12 Soups17 Warm appetizer3 Se trata del número total de recetas en cada categoría, no del número total de autores. ¿A qué se debe esto? Bueno, COUNT(*) cuenta todas las filas de cada grupo. La tabla receta contiene información en un recipe nivel - cada registro es una receta. Esta consulta cuenta las recetas (filas) de cada categoría, no los autores de las recetas. Un autor puede tener muchas recetas en cada categoría, así que para obtener la información que quieres, debes contar los autores distintos (usando COUNT(distinct author) en lugar de COUNT(*)) dentro de cada grupo. Este es un error muy común de GROUP BY. Entonces, ¿cuándo debe utilizar COUNT(*), COUNT(expression) y COUNT(distinct expression)? Veamos un ejemplo: 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 diferencia entre COUNT(*) y COUNT(expression) es visible si estamos haciendo cálculos en una columna que tiene algunos valores perdidos. Cuando hay valores perdidos, COUNT(*) contará todos los registros de un grupo y COUNT(expression) contará sólo los valores no nulos. En el ejemplo anterior, COUNT(*) y COUNT(author) dan exactamente el mismo resultado porque la columna autor no tiene valores NULL. COUNT(distinct author) nos da el número de autores distintos para cada categoría, que no es el mismo que COUNT(*). Por ejemplo, la categoría de comida fría de aperitivo contiene seis recetas de dos autores distintos. COUNT(*) cuenta el número de recetas (registros) en cada categoría, mientras que COUNT(distinct author) cuenta el número de autores distintos. Por lo tanto, si desea mostrar el número total de autores distintos por cada categoría de comida, utilice COUNT(distinct author). Esta es la consulta correcta: SELECT meal_category, count(distinct author) FROM recipes GROUP BY meal_category; GROUP BY meal_category; Para una explicación más detallada, consulte ¿Cuál es la diferencia entre COUNT(*), COUNT(1), COUNT(nombre de columna) y COUNT(nombre de columna DISTINTO)? 6. Problemas al utilizar funciones agregadas con NULLs Este es otro problema de "valores perdidos". Supongamos que quiere calcular el promedio del número total de vistas del mes anterior para cada categoría. Su colega ha calculado esas cifras, pero le gustaría que usted comprobara el resultado. Esta es su consulta: SELECT meal_category, avg(no_of_views_lst_mth) as average, FROM recipes GROUP BY meal_category; Y lo que obtienes es... 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 El resultado parece correcto y usted está seguro de que su consulta es correcta. Sin embargo, tu colega ha obtenido cifras ligeramente diferentes: 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 ¿Qué ha pasado? ¿Por qué los resultados son diferentes? En pocas palabras, los distintos resultados se deben a las diferentes interpretaciones de los valores que faltan. La columna no_of_views_lst_mth representa el número de páginas vistas totales en el mes anterior. Si una receta se creó en el mes actual, esta columna será NULA para esa fila. Por ejemplo, la receta Tarta de queso y plátano de Ally se escribió en el mes actual, por lo que no hay estadísticas para el mes anterior: meal_categorynameauthorno_of_viewsno_of_views_lst_mthauthor_id dessertsBanana CheesecakeAlly131944NULL3 La tarta de queso con plátano se publicó en el mes actual Ahora, volvamos a los promedios y sus diferentes resultados. Los promedios se calculan como la suma total de no_of_views_lst_mth dividida por el número total de registros. Si utiliza la función AVG() y hay NULLs presentes, el motor simplemente ignora los NULLs y hace los cálculos sin ellos. Esto es lo que ocurrió cuando ejecutó su consulta: los NULL se omitieron. En algunos casos, querrá reemplazar los NULLs por 0 (porque la lógica del negocio lo dicta); esto es lo que hizo su colega, que produjo cifras ligeramente diferentes. Aquí está la consulta de su colega: 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; Observe cómo los promedios de estas dos consultas tratan los NULL de forma diferente. Por ejemplo, la categoría "postres" contiene NULLs. Por lo tanto, la primera consulta omite estas filas y no las cuenta en el número total de filas; esto da el valor 144349,72. La segunda consulta sustituye todos los NULLs por cero y cuenta estas filas en la media, dando un valor menor de 129914,75. Yo diría que ambas consultas podrían ser válidas, dependiendo de cómo se quieran calcular los promedios. 7. Usando COUNT(*) con GROUP BY y un LEFT JOIN El uso de GROUP BY con una sentencia LEFT JOIN puede ser bastante confuso - especialmente con COUNT(). Veamos cómo funcionan COUNT(*) y COUNT(expression) en una sentencia LEFT JOIN. Supongamos que alguien de marketing tiene la siguiente tabla, recipes_campaigns. Contiene información sobre el número de campañas realizadas en cada categoría de comida en el mes actual: meal_categorycampaigns Bread and pastry2 Cold appetizer1 desserts3 drinks0 Main dishes3 Salads1 Side dishes2 Soups3 Warm appetizer0 brunch1 sandwiches0 campaña_recetas Además de los datos en recipes_campaigns, el responsable de marketing también quiere ver el número de recetas de cada categoría de comidas. Para ello, necesitaremos la información de la tabla recipes tabla. Así que unamos estas dos tablas por la izquierda y calculemos el número de recetas usando COUNT(*), así: 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; Este es el resultado: meal_categorycount(*) Bread and pastry7 brunch1 Cold appetizer6 desserts20 drinks7 Main dishes20 Salads8 sandwiches1 Side dishes12 Soups17 Warm appetizer3 Esto no es lo que esperábamos. La tabla recipe no contiene ninguna receta en la categoría 'brunch', así que ¿por qué entonces obtuvimos ese 1 en el resultado? ¡Esto sucede porque COUNT() se aplica al resultado de LEFT JOIN! Cuando LEFT JOIN dos tablas, la categoría 'brunch' estará presente en el resultado - incluso si no hay recetas o categorías que coincidan en la tabla recipe tabla. ¿Cómo podemos arreglar esto? Si usamos COUNT(expression) en lugar de COUNT(*), obtendremos el resultado que queremos: 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 vez que se ejecuta esto, se obtiene: meal_categorycount(author_id) Bread and pastry7 brunch0 Cold appetizer6 desserts20 drinks7 Main dishes20 Salads8 sandwiches0 Side dishes12 Soups17 Warm appetizer3 Aquí, COUNT(author_id) cuenta sólo los valores no NULL en author_id después de realizar el LEFT JOIN. No hay ningún valor en author_id para la categoría 'brunch'; en otras palabras, es NULL y el resultado para esa categoría es 0. Puede resolver los errores de GROUP BY A través de varios ejemplos, hemos explorado GROUP BY y los errores más comunes que los principiantes suelen cometer. Espero que ahora tenga una mejor idea de cómo funciona GROUP BY y qué es lo que causa esos errores extraños o resultados confusos. GROUP BY es realmente muy importante en la creación de informes. Si quiere aprender a construir buenos informes, le recomiendo nuestro Cómo crear informes básicos con SQL curso. Tiene muchos ejercicios interactivos que le permiten ganar experiencia escribiendo GROUP BY consultas para los informes. Y una mayor experiencia reduce sin duda la posibilidad de cometer errores. Tags: SQL aprender SQL agrupar por