Ir al contenido
wannacode

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:

SQLbase de datos: tienda

60 pedidos, cinco grupos, cinco filas. Cada grupo da una fila.

Los clientes por ciudad:

SQLbase de datos: tienda

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:

SQLbase de datos: tienda

SELECT order_id, COUNT(*) AS lines, ROUND(SUM(quantity * unit_price), 2) AS total
FROM order_items
WHERE order_id >= 58
GROUP BY order_id;
Paso a paso, en palabras
  1. 6 filas de order_items: los productos de los pedidos 58, 59 y 60.
  2. GROUP BY order_id: cada fila va al grupo de su order_id.
  3. 3 order_id distintos, 3 grupos. En cada uno hay 2 filas.
  4. 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 €.
  5. El grupo de 59: 2 filas, 3 × 2,50 + 2 × 3,20 = 13,90 €.
  6. El grupo de 60: 2 filas, 2 × 1,20 + 4 × 2,90 = 14,00 €.
  7. Entraron 6 filas, salieron 3: una por cada grupo.

La consulta de la escena. ROUND(…, 2) redondea la suma al céntimo:

SQLbase de datos: tienda

Pruébalo

Pedidos por cliente

¿Cuántos pedidos ha hecho cada cliente? Muestra customer_id y la cantidad.

SQLbase de datos: tienda

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:

SQLbase de datos: tienda

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:

SQLbase de datos: tienda

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:

SQLbase de datos: tienda

Míralo

La columna que no está en el grupo

Los pedidos por cliente, y al lado el estado. Parece razonable:

SQLbase de datos: tienda
1. La consulta mostró «8 | cancelled | 3». ¿Qué significa?

Los pedidos del cliente 8 muestran lo que pasa:

SQLbase de datos: tienda

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.

SQLbase de datos: tienda

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.

SQLbase de datos: tienda

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.

SQLbase de datos: tienda

Test

Ponte a prueba

1. ¿Cuántas filas devuelve SELECT status, COUNT(*) FROM orders GROUP BY status?
2. Boris no tiene ciudad. ¿Dónde está en SELECT city, COUNT(*) FROM customers GROUP BY city?
3. ¿Qué da GROUP BY customer_id, status?
4. ¿Qué es seguro en el SELECT de una consulta con GROUP BY order_id?

Creado por Ivo Gergov como parte de la campaña de Evo Tech por una educación accesible en programación ·