GROUP BY: un informe por grupos
En resumen: GROUP BY pone las filas con el mismo valor en un grupo, para que COUNT, SUM o AVG se calculen para cada grupo por separado.
Problema
El panel del almacén
El almacén quiere un panel: cuántos pedidos son nuevos, cuántos pagados, cuántos enviados. Con COUNT(*) y WHERE status = 'new' necesitarías cinco consultas, una por cada estado. Y si mañana aparece un sexto estado, el informe no lo mostrará.
Necesitas una consulta que encuentre los estados por sí sola y cuente cada uno.
La idea
GROUP BY
GROUP BY columna pone las filas con el mismo valor en la columna en un grupo. La función de agregación se calcula para cada grupo por separado:
60 pedidos, cinco grupos, cinco filas. Cada grupo da una fila.
Los clientes por ciudad:
Boris no tiene ciudad y está en un grupo aparte con city = NULL. Para GROUP BY, como para DISTINCT, todos los NULL son un grupo.
Cómo un grupo se convierte en una fila se ve mejor con pocas filas. Los últimos tres pedidos son seis filas en order_items:
SELECT order_id, COUNT(*) AS lines, ROUND(SUM(quantity * unit_price), 2) AS totalFROM order_itemsWHERE order_id >= 58GROUP BY order_id;Paso a paso, en palabras
- 6 filas de order_items: los productos de los pedidos 58, 59 y 60.
- GROUP BY order_id: cada fila va al grupo de su order_id.
- 3 order_id distintos, 3 grupos. En cada uno hay 2 filas.
- El grupo de 58 se convierte en una fila: COUNT(*) es 2, y SUM(quantity * unit_price) es 1 × 1,20 + 4 × 1,90 = 8,80 €.
- El grupo de 59: 2 filas, 3 × 2,50 + 2 × 3,20 = 13,90 €.
- El grupo de 60: 2 filas, 2 × 1,20 + 4 × 2,90 = 14,00 €.
- Entraron 6 filas, salieron 3: una por cada grupo.
La consulta de la escena. ROUND(…, 2) redondea la suma al céntimo:
Pruébalo
Pedidos por cliente
¿Cuántos pedidos ha hecho cada cliente? Muestra customer_id y la cantidad.
Solución
SELECT customer_id, COUNT(*)
FROM orders
GROUP BY customer_id;SELECT customer_id, COUNT(*) FROM orders GROUP BY customer_id. 18 filas: dos de los veinte clientes no tienen pedidos, así que no están. El cliente 1 tiene 12 pedidos, el que más.
La idea
El valor de cada pedido
En order_items un pedido ocupa varias filas, una por cada producto. Un grupo por order_id reúne las líneas de un pedido:
Ahora cada pedido es una fila: cuántos productos tiene y cuánto vale.
Un grupo también puede ser por dos columnas. Entonces un grupo contiene las filas en las que los dos valores son iguales. Los pedidos del cliente 1 por estado:
Un grupo también puede ser por un valor calculado. strftime('%Y-%m', ordered_at) toma el año y el mes de la fecha, y los pedidos se agrupan por mes:
Míralo
La columna que no está en el grupo
Los pedidos por cliente, y al lado el estado. Parece razonable:
Los pedidos del cliente 8 muestran lo que pasa:
Tres pedidos, tres estados distintos. El grupo es una fila, y tiene sitio para un valor. SQLite no dice nada y toma el estado de una de las filas. Cuál, no está prometido.
La regla: cada columna del SELECT está en GROUP BY o dentro de una agregación (COUNT, SUM, MIN…). PostgreSQL y SQL Server dan un error con una consulta así, y MySQL también con su configuración por defecto desde la versión 5.7. SQLite la acepta y muestra algo que parece una respuesta.
Si quieres los estados, agrupa por las dos columnas: GROUP BY customer_id, status.
Más precisamente, para curiosos
SQLite tiene una peculiaridad que está en su documentación: si la consulta tiene exactamente un MIN o un MAX, la columna libre sale de la fila con el valor más pequeño o más grande. SELECT customer_id, MAX(ordered_at), id FROM orders GROUP BY customer_id da el número del último pedido. Esto es solo de SQLite. Las demás bases lo rechazan, y en el módulo de subconsultas veremos cómo hacerlo en todas partes.
Pruébalo
Los más vendidos
¿Qué cinco productos han vendido más unidades? Muestra product_id y las unidades en una columna llamada sold, el más vendido primero.
Solución
SELECT product_id, SUM(quantity) AS sold
FROM order_items
GROUP BY product_id
ORDER BY sold DESC
LIMIT 5;GROUP BY product_id, SUM(quantity) AS sold, luego ORDER BY sold DESC LIMIT 5. Primero va el producto 13 con 31 unidades: los pepinos, que están agotados. Quizá sea hora de un nuevo pedido al proveedor.
Ejercicio
Dos informes
1. ¿Cuántos productos y cuántas unidades en existencia hay en cada categoría?
Muestra category_id, la cantidad de productos y la suma de sus existencias.
Solución
SELECT category_id, COUNT(*), SUM(stock)
FROM products
GROUP BY category_id;SELECT category_id, COUNT(*), SUM(stock) FROM products GROUP BY category_id. Siete grupos: seis categorías y NULL para la tarjeta de regalo. Sus 999 tarjetas no son mercancía en un estante, así que en un informe real la quitaríamos con WHERE category_id IS NOT NULL.
2. Contabilidad quiere la cantidad de pedidos de cada mes de 2026, ordenada por mes.
Muestra el mes (año-mes) y la cantidad de pedidos de cada mes de 2026, en el orden de los meses.
Solución
SELECT strftime('%Y-%m', ordered_at) AS month, COUNT(*)
FROM orders
WHERE ordered_at >= '2026-01-01'
GROUP BY strftime('%Y-%m', ordered_at)
ORDER BY month;WHERE ordered_at >= '2026-01-01' conserva los pedidos de 2026, GROUP BY strftime('%Y-%m', ordered_at) los divide por mes, y ORDER BY month los ordena. Diez meses, de enero a octubre. Por qué ORDER BY puede usar el alias month, lo veremos en la última lección del módulo.
Test
Ponte a prueba
Lecciones relacionadas
Sección «Lecciones relacionadas»- Se basa en: ORDER BY, LIMIT y DISTINCT · Aritmética en una consulta · Funciones de fecha · Funciones de agregación: COUNT, SUM, AVG
- Continúa en: HAVING: una condición para los grupos · El orden de ejecución de una consulta · LEFT JOIN: también las filas sin pareja · Muchas tablas, y una tabla unida consigo misma
- Ejercicios sobre el tema: Resumir