Lesson 19 of 25· Agrupar datos con GROUP BY
Imagina que tu jefe entra y pregunta: "¿Cuánto vendió cada categoría en la tienda?". Ya sabes sumar: SUM(precio_unitario * cantidad) te da el ingreso total. Pero eso te da una sola cifra para toda la tienda. Lo que te piden es una cifra por categoría: una para Accesorios, otra para Monitores, otra para Audio…
Esa palabra — por — es la señal inequívoca de que necesitas GROUP BY. En esta lección aprenderás a resumir datos por grupo: ingresos por categoría, número de ventas por ciudad y cualquier pregunta con "por cada…". Al terminar podrás responder tú mismo esa pregunta del jefe con una sola consulta.
Trabajamos sobre la tabla
ventasdel dataset de la tienda: cada fila es una venta con suproducto,categoria,ciudad,precio_unitario,cantidadymetodo_pago.
Antes de agrupar, recordemos qué hace una agregación sin GROUP BY: colapsa todas las filas de la tabla en una sola fila de resumen. Ejecuta esto:
-- Ingreso total de TODA la tienda: una única fila de resumen
SELECT
SUM(precio_unitario * cantidad) AS ingreso_total,
COUNT(*) AS num_ventas
FROM ventas;Obtienes una fila: ingreso_total = 20 764 700 y num_ventas = 20. Correcto, pero indiferenciado: no sabes de dónde viene ese dinero. Necesitamos partir ese total por categoría.
GROUP BY categoria le dice a PostgreSQL: "antes de sumar, junta las filas que comparten la misma categoría; luego calcula las agregaciones dentro de cada grupo por separado". En lugar de una fila, obtienes una fila por categoría distinta.
SELECT
categoria,
SUM(precio_unitario * cantidad) AS ingresos,
COUNT(*) AS num_ventas
FROM ventas
GROUP BY categoria
ORDER BY ingresos DESC;Fíjate en la estructura del resultado: la columna categoria identifica cada grupo, y a su lado las agregaciones (ingresos, num_ventas) resumen solo las filas de ese grupo. La respuesta a la pregunta del jefe: Computadores lidera con 7 898 000, seguido de Audio (3 030 000) y Monitores (2 896 000). Si sumas todos los ingresos de vuelta, obtienes exactamente 20 764 700 — el total global del paso 1, ahora desglosado.
ORDER BY ingresos DESCno forma parte de la agrupación: solo ordena las filas ya agrupadas para leerlas cómodamente de mayor a menor. Puedes ordenar por el alias de una columna agregada sin problema.
GROUP BY por dentro?Mentalmente, GROUP BY categoria reparte las filas en "cubos", uno por cada valor distinto de categoria, y luego aplica la agregación a cada cubo:
Aquí está el concepto que hay que grabar a fuego:
Toda columna que aparezca en el
SELECTy NO esté dentro de una función de agregación DEBE estar en elGROUP BY.
¿Por qué? Porque cada fila del resultado representa un grupo entero, no una fila individual. Si pides una columna "suelta" que tiene varios valores distintos dentro del grupo, PostgreSQL no sabría cuál mostrar. Por ejemplo: dentro del grupo Accesorios hay ventas en Bogotá, Cali, Medellín y Barranquilla — ¿qué ciudad debería enseñar en esa única fila? No tiene respuesta, así que se niega. Ejecuta esto y lee el error:
-- ❌ Falla a propósito: 'ciudad' no está agregada ni en el GROUP BY
SELECT
categoria,
ciudad,
SUM(precio_unitario * cantidad) AS ingresos
FROM ventas
GROUP BY categoria;PostgreSQL responde con algo como:
ERROR: column "ventas.ciudad" must appear in the GROUP BY clause
or be used in an aggregate functionTienes dos formas legítimas de arreglarlo, según lo que de verdad quieras:
| Qué quieres | Solución |
|---|---|
| Ver el detalle por categoría y ciudad | Añade ciudad al GROUP BY → un grupo por cada par (categoría, ciudad) |
| No te importa la ciudad en el resumen | Quítala del SELECT |
La clave: si una columna es la que define el grupo, va en el GROUP BY; si es un dato que quieres resumir, va dentro de una agregación (SUM, COUNT, AVG, MIN, MAX). No hay una tercera opción.
GROUP BY no es solo para sumar dinero. Combínalo con COUNT(*) para contar cuántas filas cae en cada grupo. Respondamos "¿cuántas ventas hubo en cada ciudad?":
SELECT
ciudad,
COUNT(*) AS num_ventas
FROM ventas
GROUP BY ciudad
ORDER BY num_ventas DESC;Resultado: Bogotá 8, Medellín 5, Cali 4, Barranquilla 3 (8 + 5 + 4 + 3 = 20, todas las ventas). Cambia COUNT(*) por SUM(precio_unitario * cantidad) y responderás "¿cuánto facturó cada ciudad?" con la misma estructura. Ese es todo el poder de GROUP BY: eliges por qué agrupar y qué resumir, y la forma de la consulta no cambia.
GROUP BY col colapsa las filas con el mismo valor de col en una fila por grupo.SUM, COUNT, AVG…) se calculan dentro de cada grupo, no sobre toda la tabla.SELECT que no sea agregada tiene que estar en el GROUP BY.Hora de escribir tú la consulta. Resuelve la tarea y pulsa Comprobar: el sistema compara tu resultado con el esperado.
Escribe una consulta que devuelva, para cada ciudad, cuántas ventas se registraron. La salida debe tener dos columnas: ciudad y num_ventas (usa exactamente ese alias), ordenadas de más ventas a menos.
-- Objetivo: número de ventas por ciudad, de mayor a menor.
-- Devuelve exactamente dos columnas: ciudad y num_ventas.
-- TODO: completa la consulta con COUNT(*), GROUP BY y ORDER BY.
SELECT
ciudad
-- añade aquí el conteo de ventas
FROM ventas;Antes de cerrar, responde mentalmente (sin volver a mirar arriba):
SELECT categoria, metodo_pago, COUNT(*) FROM ventas GROUP BY categoria; — ¿por qué y cómo lo arreglas? (Porque metodo_pago no está agregada ni en el GROUP BY; se soluciona añadiéndola al GROUP BY o quitándola del SELECT.)SELECT categoria, COUNT(*) FROM ventas GROUP BY categoria;? (Una por cada categoría distinta en la tabla ventas.)GROUP BY y qué va en la agregación? (Agrupas por metodo_pago y agregas con SUM(precio_unitario * cantidad).)Si las tres te salieron con seguridad, ya dominas la mecánica de GROUP BY. En la siguiente lección agruparemos por varias columnas a la vez para desgloses más finos.
Free