Volver a la lista de artículos Artículos
Lectura de 9 minutos

Cómo Agrupar por Múltiples Columnas en SQL

Al analizar grandes conjuntos de datos, a menudo se crean agrupaciones y se aplican funciones de agregación para encontrar totales o promedios. En estos casos, el uso de la cláusula GROUP BY con varias columnas despliega todo su potencial.

GROUP BY es una cláusula del comando SELECT. Permite calcular diversas estadísticas para un grupo de filas. Por ejemplo, puede utilizar GROUP BY con una tabla de empleados para saber cuántos empleados son de cada sexo. O puede agrupar por varias columnas para determinar la edad media de los vehículos de cada marca y modelo en una tabla vehicle_fleet. En este artículo, examinaremos en detalle cómo funciona la agrupación por varias columnas.

Este artículo asume que ya sabes cómo utilizar GROUP BY en una consulta SQL. ¿No estás familiarizado con GROUP BY? La mejor forma de aprender ésta y otras construcciones SQL básicas es con nuestro curso interactivo SQL para principiantes. Contiene 129 ejercicios prácticos. Cada ejercicio contiene una breve explicación y una tarea que resolver. Con cada ejercicio completado, ganarás confianza en tus habilidades SQL. Este curso también es una buena forma de repasar las funciones básicas de SQL si tus conocimientos están un poco oxidados.

Bien, comencemos con un repaso de un caso de uso simple para GROUP BY.

GROUP BY 1 Columna

Cada combinación de los valores de columna(s) especificados en la cláusula GROUP BY constituye un grupo; el comando SELECT con una cláusula GROUP BY muestra una sola fila para cada grupo. También es bueno tener en cuenta que GROUP BY permite aplicar funciones de agregado en columnas no incluidas en el subconjunto destacado.

Veamos un ejemplo. He creado una tabla llamada WorldWideFriends que almacena datos sobre mis amigos en distintas partes del mundo:

FriendNameCityStateCountry
MaríaAcapulcoGuerreroMéxico
FernandoCaracasDistrito CapitalVenezuela
GersonMedellínAntioquíaColombia
MónicaBogotáCundinamarcaColombia
PaulBogotáCundinamarcaColombia
KevinLexingtonKentuckyUSA
CeciliaGodoy CruzMendozaArgentina
PabloAtlántidaCanelonesUruguay
AndreaCdad. MendozaMendozaArgentina
MarlonSao PauloSao PauloBrasil
JoaoRio de JaneiroRio de JaneiroBrasil
AndrésBarilocheRío NegroArgentina
MarianoMiamiFloridaUSA

Me gustaría utilizar la información de esta tabla para hacer alguna investigación - por ejemplo, para obtener una lista de los países donde viven mis amigos, incluyendo el número de amigos que viven en cada país.

Si quisiera saber cuántos amigos tengo en cada país, utilizaría GROUP BY junto con la función de agregado COUNT():

SELECT 
  Country, 
  COUNT(*) AS HowMany
FROM WorldWideFriends
GROUP BY Country;

Esta consulta me da un conjunto de resultados que condensa las filas con el mismo país en una sola fila, mientras que COUNT(*) me dice cuántas filas repetidas hay para cada país:

CountryHowMany
Argentina3
Venezuela1
Colombia3
Brasil2
USA2
México1
Uruguay1

La consulta anterior me da la información que necesitaría si, por ejemplo, tuviera que elegir a qué país viajar para reunirme con el mayor número posible de amigos. Si quieres leer más sobre el uso básico de GROUP BY, te recomiendo nuestros artículos sobre Qué es GROUP BY en SQL y Cómo utilizar GROUP BY.

Sin embargo, aunque viaje a un país en el que viven muchos de mis amigos, puede que éstos se encuentren en distintos estados. Puede que no tenga tiempo de viajar de un estado a otro para visitarlos a todos. Así que tengo que refinar un poco mi búsqueda para encontrar la ubicación geográfica donde hay una mayor concentración de mis amigos.

Agrupar por 2 columnas

Ahora necesito saber cómo se distribuyen mis amigos por estados y países. Puedo averiguarlo añadiendo la columna State a mi anterior GROUP BY País (separándolas con comas) y en la cláusula SELECT. La consulta queda así

SELECT 
  Country, 
  State, 
  COUNT(*) AS HowMany
FROM WorldWideFriends
GROUP BY Country, State;

Observando los resultados de esta consulta, podemos ver que algunos de los países que antes aparecían en una sola fila ahora aparecen en varias filas. La razón es que cuando añadimos el campo State, la consulta debe reunir los grupos con las filas que tienen el mismo valor tanto en Country como en State.

En la consulta anterior, la fila correspondiente a 'Colombia' tenía un 3 en el campo HowMany. En este caso, "Colombia" aparece en dos filas con valores diferentes para el Estado: una para "Antioquia" y otra para "Cundinamarca". En el campo HowMany, la fila correspondiente a "Antioquia" indica 1, mientras que la fila correspondiente a "Cundinamarca" indica 2. Esto significa que, en la lista desagregada, hay dos filas con Country = 'Colombia' y State = 'Cundinamarca', y sólo una con Country = 'Colombia' y State = 'Antioquia'.

La suma de los valores HowMany de estas dos filas coincide lógicamente con el valor HowMany anterior de la fila correspondiente a 'Colombia'. Lo mismo ocurrirá para cualquiera de los otros países que estén divididos en varias filas con diferentes estados.

CountryStateHowMany
ArgentinaMendoza2
ArgentinaRío Negro1
VenezuelaDistrito Capital1
ColombiaAntioquía1
ColombiaCundinamarca2
BrasilRio de Janeiro1
BrasilSao Paulo1
USAKentucky1
USAFlorida1
MéxicoGuerrero1
UruguayCanelones1

Agrupar por varias columnas

Por último, si mi intención es que mi viaje sea lo más corto posible y aún así visitar al mayor número de amigos, sólo tengo que añadir la columna City a mi consulta -tanto en SELECT como en GROUP BY - para ver qué ciudades tienen el mayor número de amigos:

SELECT 
  Country, 
  State, 
  City, 
  COUNT(*) AS HowMany
FROM WorldWideFriends
GROUP BY Country, State, City;

Cuando añadimos columnas a GROUP BY, aumenta el número de filas del resultado. Esto se debe a que crece el número de combinaciones de valores posibles. Cuando añado la columna City al SQL GROUP BY, el tamaño del resultado crece considerablemente:

CountryStateCityHowMany
ArgentinaMendozaCdad. Mendoza1
ArgentinaMendozaGodoy Cruz1
ArgentinaRío NegroBariloche1
VenezuelaDistrito CapitalCaracas1
ColombiaAntioquíaMedellín1
ColombiaCundinamarcaBogotá2
BrasilRio de JaneiroRio de Janeiro1
BrasilSao PauloSao Paulo1
USAKentuckyLexington1
USAFloridaMiami1
MéxicoGuerreroAcapulco1
UruguayCanelonesAtlántida1

En este caso, creo que sería mejor ver sólo las ciudades en las que hay más de uno de mis amigos. Así que para resumir los resultados, utilizaré la cláusula HAVING. Esta cláusula me permite establecer una condición sobre los resultados de las funciones agregadas al utilizar GROUP BY. En este caso, la condición a aplicar será que el recuento de amigos sea mayor que 1 (COUNT(*) > 1). Tras incorporar la cláusula HAVING, la consulta queda de la siguiente manera:

SELECT Country, State, City, COUNT(*) AS HowMany
FROM WorldWideFriends
GROUP BY Country, State, City
HAVING COUNT(*) > 1;

De esta forma, el resultado de la consulta se reduce a una única fila que me muestra la única ciudad en la que hay más de uno de mis amigos:

CountryStateCityHowMany
ColombiaCundinamarcaBogotá2

Otras formas de utilizar GROUP BY con múltiples columnas

Es habitual utilizar GROUP BY con múltiples columnas cuando dos o más de las columnas de un resultado de consulta forman una jerarquía de clasificaciones con varios niveles. Este tipo de jerarquías se encuentran en muchos ámbitos, como por ejemplo:

  • Datos detallados de ventas con la fecha de venta dividida en año, trimestre y mes.
  • El catálogo de productos de un fabricante organizado por familia, marca, línea, modelo.
  • La nómina de los empleados de una empresa organizada por dirección, sector, departamento.

En todos estos casos, se pueden utilizar diferentes subconjuntos de columnas en GROUP BY para ir de lo general a lo particular.

Uso de agrupar por varias columnas: Agrupar una jerarquía

Veamos un ejemplo de conjunto de resultados de datos de ventas. Supongamos que tiene una vista llamada ViewSales que devuelve la siguiente información:

YearQuarterMonthDateQuantityUnit_Price
202141111/15/2021516.08
2021388/2/2021117.06
2022244/5/2022219.48
2022255/21/2022117.06
202141111/17/2021218.50
2022244/5/2022118.08
2022388/16/2022515.26

Es fácil ver que los primeros campos de esta tabla forman una jerarquía, con el año como nivel superior y la fecha como nivel inferior. Utilizando GROUP BY y la función SUM(), podemos obtener los importes totales de las ventas por Year

, por

Quarter, por

Month o por Date. Si desea obtener el total de unidades vendidas y el precio unitario medio por Year y Quarter, debe especificar esas dos columnas en SELECT y en GROUP BY:

SELECT 
  Year, 
  Quarter, 
  SUM(Quantity) AS TotalQty, 
  AVG(Unit_Price) as AvgUnit_Prc
FROM ViewSales
GROUP BY Year, Quarter;

El resultado será:

YearQuarterTotalQtyAvgUnit_Prc
20214717.29
20213117.06
20222418.21
20223515.26

Tenga en cuenta que, aunque existe un orden jerárquico, los datos de las distintas columnas de agrupación son independientes entre sí. Esto significa que si agrupa sólo por Quarter en lugar de por Year más Quarter, los cálculos agregados combinarán la información del mismo trimestre para todos los años (es decir, todos los Q2 tendrán una fila):

SELECT 
  Quarter, 
  SUM(Quantity) AS TotalQty,
  AVG(Unit_Price) as AvgUnit_Prc
FROM ViewSales
GROUP BY Quarter;
QuarterTotalQtyAvgUnit_Prc
4717.29
3616.16
2418.21

No se trata de un error, sólo hay que entender que los resultados expresan percepciones diferentes. La segunda consulta permite comparar el rendimiento de las ventas entre distintos trimestres independientemente del año (por ejemplo, para detectar factores estacionales que afectan a las ventas en la misma época de cada año), mientras que la primera compara las ventas de cada año y trimestre en particular.

Uso de agrupar por varias columnas: Agrupación no jerárquica

En el ejemplo anterior, vimos que agrupar por múltiples columnas nos permite ir de lo general a lo particular cuando tenemos conjuntos de datos con columnas que forman una jerarquía de datos. Pero en situaciones en las que un conjunto de resultados está formado por columnas que no forman una jerarquía, utilizar GROUP BY con múltiples columnas nos permite descubrir verdades ocultas en grandes conjuntos de datos; combina atributos que a primera vista no están relacionados entre sí.

Por ejemplo, imaginemos que tenemos una tabla llamada Downloads que almacena información sobre las personas que han descargado películas de un servicio de streaming en los últimos dos años. Esa tabla tiene una fila por cada descarga, y cada fila incluye la siguiente información sobre cada persona que descargó una película:

  • Age
  • Gender
  • Nationality

Cada fila también captura estos atributos sobre cada película descargada:

  • Genre
  • Year
  • Country

Utilizando GROUP BY con varias de estas columnas y la función COUNT(*), podemos detectar correlaciones entre las columnas. Por ejemplo, para averiguar las preferencias de género de las películas según la edad, escribiríamos:

SELECT 
  Age, 
  Genre, 
  COUNT(*) AS Downloads
FROM Downloads
GROUP BY Age, Genre

Como resultados, obtendríamos algo así:

AgeGenreDownloads
18Horror12,945
18Comedy15,371
19Drama25,902
19Horror11,038
21Comedy37,408

También podríamos utilizar GROUP BY 3 columnas, para averiguar (por ejemplo) las preferencias de género por sexo y nacionalidad:

SELECT 
  Gender, 
  Nationality, 
  Genre, 
  COUNT(*) AS Downloads
FROM Downloads
GROUP BY Gender, Nationality, Genre

Y obtendríamos algo así

GenderNationalityGenreDownloads
MaleFrenchHorror102,044
MaleFrenchComedy149,290
MaleGermanHorror80,104
FemaleFrenchHorror91.668
FemaleGermanComedy50,103
FemaleGermanDrama61,440
OtherFrenchDrama77,993
OtherGermanComedy25,484

GROUP BY con múltiples columnas devuelve información facetada

GROUP BY es una poderosa herramienta para extraer información de grandes conjuntos de datos que son difíciles de manipular de cualquier otra forma. Utilizando GROUP BY con múltiples columnas, puede aprovechar todo su potencial para exponer las verdades de un conjunto de datos, permitiéndole ver diferentes facetas del mismo. Para hacerlo con éxito, es fundamental que entiendas -y sepas explicar- qué representa un conjunto de resultados SQL agrupado por múltiples columnas.

Si estás planeando hacer un trabajo serio de análisis de datos, entonces deberías tomar nuestro curso interactivo SQL para principiantes para aprender sobre todas las herramientas que SQL puede ofrecer. Además, sigue estos enlaces si necesitas más explicaciones sobre GROUP BY o quieres ver más ejemplos de GROUP BY en SQL.