GROUP BY y HAVING en SQL: COUNT, SUM y AVG con ejemplos

Actualizado el 29 de septiembre de 2026

Hasta ahora cada fila del resultado correspondía a una fila de la tabla. Las funciones de agregación hacen otra cosa: resumen muchas filas en un solo valor, como un total, un promedio o una cantidad. Con GROUP BY ese resumen se calcula por grupo: el stock total por categoría, el promedio de ventas por mes.

Todos los ejemplos usan esta tabla de productos de una tienda. Fíjate en que el escritorio no tiene stock registrado (NULL), que no es lo mismo que tener 0.

Estructura
CREATE TABLE productos (
  id        INTEGER PRIMARY KEY,
  nombre    TEXT,
  categoria TEXT,
  precio    INTEGER,
  stock     INTEGER
);
productos
idnombrecategoriapreciostock
1TecladoComputación2599012
2MouseComputación1299030
3MonitorComputación1599904
4AudífonosAudio349900
5ParlanteAudio499907
6SillaMuebles899903
7EscritorioMuebles129990NULL

Funciones de agregación

SELECT COUNT(*)    AS productos,
       SUM(stock)  AS stock_total,
       AVG(precio) AS precio_promedio,
       MIN(precio) AS mas_barato,
       MAX(precio) AS mas_caro
FROM productos;
productosstock_totalprecio_promediomas_baratomas_caro
75671990.012990159990

Sin GROUP BY, toda la tabla es un solo grupo y el resultado tiene una fila. Las funciones de agregación ignoran los NULL: SUM(stock) suma los seis stocks conocidos. COUNT(*) cuenta filas, pero COUNT(stock) cuenta valores no nulos: da 6, no 7.

GROUP BY: un resumen por grupo

SELECT categoria, COUNT(*) AS cantidad
FROM productos
GROUP BY categoria;
categoriacantidad
Audio2
Computación3
Muebles2

GROUP BY categoria junta las filas que tienen la misma categoría y calcula la agregación para cada grupo. La regla clave: en el SELECT solo pueden ir las columnas del GROUP BY y funciones de agregación. Pedir el nombre no tendría sentido: cada grupo tiene varios nombres.

SELECT categoria, ROUND(AVG(precio)) AS promedio
FROM productos
GROUP BY categoria;
categoriapromedio
Audio42490.0
Computación66323.0
Muebles109990.0

El promedio exacto de Computación es 66323.333…; ROUND lo redondea, aunque en SQLite el resultado sigue siendo decimal (66323.0).

HAVING: filtrar grupos

WHERE filtra filas antes de agrupar; HAVING filtra grupos después, y por eso puede usar funciones de agregación:

SELECT categoria, COUNT(*) AS cantidad
FROM productos
GROUP BY categoria
HAVING COUNT(*) >= 3;
categoriacantidad
Computación3

Una consulta puede tener ambos. El orden de ejecución ayuda a entenderlo: FROM → WHERE (filas) → GROUP BY → HAVING (grupos) → SELECT → ORDER BY → LIMIT.

Errores comunes

Usar una agregación en el WHERE

SELECT categoria FROM productos
WHERE COUNT(*) > 1
GROUP BY categoria;
-- Error: misuse of aggregate: COUNT()

Cuando se evalúa el WHERE todavía no existen los grupos, así que no hay nada que contar. Las condiciones sobre agregaciones van en HAVING.

Columnas que no están en el GROUP BY

SELECT categoria, nombre FROM productos GROUP BY categoria falla en PostgreSQL ("must appear in the GROUP BY clause or be used in an aggregate function"). SQLite, en cambio, la ejecuta y devuelve un nombre cualquiera de cada grupo, lo que es peor: el resultado parece correcto y no lo es. Si necesitas "el producto más caro de cada categoría", la herramienta es una subconsulta (ver la guía siguiente).

COUNT(*) en vez de COUNT(columna)

En Muebles, COUNT(*) es 2 y COUNT(stock) es 1, porque el escritorio no tiene stock registrado. Pregúntate qué quieres contar: filas (COUNT(*)) o valores conocidos de una columna (COUNT(columna)).

Ejercicios resueltos

Intenta resolver cada ejercicio antes de abrir la solución: equivocarse y corregir es la parte que más enseña.

1.Productos por categoría

Escribe una consulta que muestre cada categoría y cuántos productos tiene, de la que tiene más a la que tiene menos. Si dos categorías empatan, ordénalas alfabéticamente.

Ver solución
Solución
SELECT categoria, COUNT(*) AS cantidad
FROM productos
GROUP BY categoria
ORDER BY cantidad DESC, categoria;
categoriacantidad
Computación3
Audio2
Muebles2

Se agrupa por categoría y se cuenta cada grupo. El ORDER BY puede usar el alias cantidad porque se evalúa después del SELECT. Audio y Muebles empatan con 2: sin la segunda columna del ORDER BY, la base de datos puede devolverlas en cualquier orden (SQLite, de hecho, pone Muebles primero).

2.Categorías caras

Escribe una consulta que muestre las categorías cuyo precio promedio supera los 50.000, junto con ese promedio redondeado.

Ver solución
Solución
SELECT categoria, ROUND(AVG(precio)) AS promedio
FROM productos
GROUP BY categoria
HAVING AVG(precio) > 50000;
categoriapromedio
Computación66323.0
Muebles109990.0

La condición es sobre el promedio de cada grupo, así que va en HAVING. Audio queda fuera con un promedio de 42.490. Computación entra aunque dos de sus tres productos son baratos: el monitor sube el promedio, un buen recordatorio de que el promedio es sensible a los valores extremos.

3.Stock por categoría, sin los productos más caros

Escribe una consulta que muestre el stock total de cada categoría considerando solo los productos de menos de 100.000, ordenado de mayor a menor stock.

Ver solución
Solución
SELECT categoria, SUM(stock) AS stock_total
FROM productos
WHERE precio < 100000
GROUP BY categoria
ORDER BY stock_total DESC;
categoriastock_total
Computación42
Audio7
Muebles3

Aquí el filtro es sobre productos individuales, no sobre grupos, así que va en WHERE, antes de agrupar. Se descartan el monitor y el escritorio, y después se suma el stock de lo que queda: Computación suma 12 + 30, Audio 0 + 7 y Muebles solo la silla.

Practica SQL con ejercicios a tu nivel

En Coditer resuelves ejercicios en el navegador, con tests automáticos que revisan tu código y una IA que te da pistas cuando te atascas. Practicar es gratis.