Saltar al contenido
Bases de datos con SQL
Todos los cursos Ir al ejercicio →

Agrupar y resumir

  • ⏱ 55 minutos
  • 📶 Nivel: principiante
  • 🧩 Incluye ejercicio

💡 🎯 Al terminar esta lección podrás…

  • Usar COUNT, SUM, AVG, MIN y MAX.
  • Agrupar con GROUP BY y combinarlo con JOIN.
  • Filtrar grupos con HAVING y distinguirlo de WHERE.
  • Manejar los NULL en agregaciones con COUNT(columna) y COALESCE.

1.Funciones de agregación

Hasta ahora cada fila del resultado era una fila de la tabla. Las funciones de agregación resumen muchas filas en un solo valor:

FunciónQué calcula
COUNT(*)Cuántas filas hay
SUM(col)La suma de los valores
AVG(col)El promedio
MIN(col) / MAX(col)El menor y el mayor valor
Un resumen de todo el catálogo
SELECT COUNT(*)    AS cuantos,
       SUM(stock)   AS stock_total,
       AVG(precio)  AS promedio,
       MIN(precio)  AS barato,
       MAX(precio)  AS caro
FROM productos;

Resultado esperado

cuantosstock_totalpromediobaratocaro
8203258.5515.00899.00

Sin GROUP BY, toda la tabla (o las filas que pasen el WHERE) se resume en una sola fila. No puedes mezclar una columna normal con una agregada si no la agrupas.

⚠️ Importante · COUNT(*) frente a COUNT(columna)

COUNT(*) cuenta filas; COUNT(columna) cuenta solo las filas donde esa columna no es NULL. Del mismo modo, SUM, AVG, MIN y MAX ignoran los NULL.

2.Cómo tratan los NULL

Al unir clientes con pedidos con LEFT JOIN (lección 5), Diego aparece con NULL en el pedido. Mira la diferencia:

COUNT(*) y COUNT(p.id)
SELECT COUNT(*) AS filas, COUNT(p.id) AS con_pedido
FROM clientes c
LEFT JOIN pedidos p ON p.cliente_id = c.id;

Resultado esperado

filascon_pedido
54

Hay 5 filas (4 pedidos y la fila de Diego), pero solo 4 tienen pedido. Elegir bien entre COUNT(*) y COUNT(columna) es el error más común al contar «cuántos hay».

3.GROUP BY: un resumen por grupo

GROUP BY reúne las filas que comparten el mismo valor en una columna y aplica la función a cada grupo:

Resumen por categoría
SELECT categoria,
       COUNT(*)    AS cuantos,
       AVG(precio) AS promedio,
       SUM(stock)  AS stock_total
FROM productos
GROUP BY categoria
ORDER BY categoria;

Resultado esperado

categoriacuantospromediostock_total
Accesorios115.00100
Audio294.4525
Pantallas2774.5011
Periféricos3105.1767

La regla: toda columna del SELECT debe estar en el GROUP BY o dentro de una función de agregación. Aquí, categoria está agrupada y el resto va dentro de COUNT, AVG y SUM.

📌 Nota · Qué pasa si se incumple

PostgreSQL rechaza una columna no agrupada. SQLite lo permite y elige un valor cualquiera del grupo, lo que da resultados engañosos. Escribe siempre las consultas como si el motor fuera estricto.

4.Agrupar con JOIN: informes reales

Lo potente llega al combinar JOIN y GROUP BY. ¿Cuántos pedidos ha hecho y cuánto ha gastado cada cliente? El gasto de cada línea es cantidad × precio.

Gasto por cliente
SELECT c.nombre,
       COUNT(DISTINCT p.id) AS pedidos,
       COALESCE(SUM(l.cantidad * pr.precio), 0) AS gasto
FROM clientes c
LEFT JOIN pedidos p       ON p.cliente_id = c.id
LEFT JOIN lineas_pedido l ON l.pedido_id  = p.id
LEFT JOIN productos pr    ON pr.id        = l.producto_id
GROUP BY c.id
ORDER BY gasto DESC;

Resultado esperado

nombrepedidosgasto
Luis Pérez1929.00
Marta Ruiz1334.50
Ana Torres2315.50
Diego Soto00.00

5.HAVING: filtrar grupos

WHERE filtra filas antes de agrupar. Para filtrar grupos ya calculados (por ejemplo «solo las categorías con 2 o más productos») se usa HAVING:

Categorías con al menos 2 productos
SELECT categoria, COUNT(*) AS cuantos
FROM productos
GROUP BY categoria
HAVING COUNT(*) >= 2;

Resultado esperado

categoriacuantos
Audio2
Pantallas2
Periféricos3

Y puedes combinar ambos: primero WHERE descarta los productos baratos y después HAVING exige 2 o más por categoría:

Productos de más de 50 y categorías con 2 o más
SELECT categoria, COUNT(*) AS cuantos
FROM productos
WHERE precio > 50
GROUP BY categoria
HAVING COUNT(*) >= 2;

Resultado esperado

categoriacuantos
Audio2
Pantallas2
Periféricos2

Esto es el orden en que el motor trabaja:

FROM / JOINWHEREGROUP BYHAVINGSELECTORDER BYLIMIT

Por eso en WHERE no se puede usar COUNT(*) (los grupos aún no existen) y en HAVING sí.

6.Pruébalo: laboratorio de resúmenes

Elige la función, si quieres agrupar por categoría y si quieres exigir al menos 2 productos por grupo. Cada combinación es una consulta real ejecutada en SQLite sobre productos.

📊 Laboratorio de GROUP BY y HAVING

    

🧪 Ejemplo · Experimentos

1) Sin agrupar, cada función devuelve una sola fila. 2) Activa GROUP BY: ahora una por categoría. 3) Activa HAVING con COUNT(*): desaparece Accesorios, que solo tiene un producto. 4) Mira que HAVING solo se puede activar si hay GROUP BY.

7.Errores frecuentes

📒 Apuntes para llevar

  • COUNT, SUM, AVG, MIN y MAX resumen muchas filas en un valor.
  • COUNT(*) cuenta filas; COUNT(col) cuenta las que no son NULL. El resto de agregaciones ignoran los NULL.
  • GROUP BY col calcula la agregación por cada valor distinto de col.
  • Toda columna del SELECT debe estar agrupada o dentro de una función de agregación.
  • WHERE filtra filas antes de agrupar; HAVING filtra grupos después.
  • Orden de ejecución: FROM/JOIN → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT.
  • COALESCE(x, 0) sustituye NULL por un valor; COUNT(DISTINCT x) cuenta valores distintos.

8.Glosario

TérminoSignificado
AgregaciónCálculo que resume varias filas en un solo valor.
COUNT(*)Cuenta las filas del grupo o de la tabla.
SUM / AVGSuma y promedio de los valores de una columna, ignorando NULL.
MIN / MAXMenor y mayor valor de una columna.
GROUP BYCláusula que reúne las filas con el mismo valor para calcular un resumen por grupo.
HAVINGCláusula que filtra grupos después de calcular las agregaciones.
COALESCEFunción que devuelve el primer valor que no es NULL.
DISTINCTPalabra que elimina duplicados, también dentro de COUNT(DISTINCT …).

🧠 Comprueba lo aprendido

Elige una respuesta en cada pregunta. Verás al instante si acertaste y por qué.

¿Qué devuelve SELECT COUNT(*) FROM productos;?

¿Cuál es la diferencia entre COUNT(*) y COUNT(columna)?

¿Qué hace GROUP BY categoria?

¿Cómo se filtran las categorías que tienen al menos 2 productos?

¿Cuál es el orden correcto de ejecución?

Tu progreso se guarda en este navegador y se refleja en el índice del curso.

💡 🚀 ¡Ahora te toca!

La práctica fija lo aprendido. Pasa al ejercicio de esta lección.

Ir al ejercicio