Filtrar grupos con HAVING
Lección 4.3 · Tiempo de lectura: ~7 min · Tareas de práctica ↓
Al usar GROUP BY con funciones de agregación, a menudo necesitas filtrar los grupos según sus resultados agregados. HAVING es el operador que filtra grupos, igual que WHERE filtra filas individuales. En esta lección aprenderás las diferencias entre WHERE y HAVING, su sintaxis y ejemplos prácticos con Sakila. Al terminar, usarás HAVING con seguridad para analizar datos en profundidad.
En las lecciones anteriores aprendiste a usar GROUP BY para agrupar datos y aplicar funciones de agregación. Ahora llega el siguiente paso: filtrar los propios grupos con condiciones sobre los valores agregados.
HAVING lo hace permitiendo condiciones después de agrupar.
100 conserva 395 de 599 clientes" width="100%">
WHERE frente a HAVING
- WHERE filtra filas antes de agrupar
- HAVING filtra grupos después de agregar
SELECT column1, COUNT(*) AS cnt
FROM table
WHERE column1 > 100 -- filter BEFORE grouping
GROUP BY column1
HAVING COUNT(*) > 10; -- filter AFTER grouping
Sintaxis de HAVING
Estructura básica:
SELECT column1, AGG_FUNCTION(column2)
FROM table
GROUP BY column1
HAVING condition;
La condición de HAVING suele incluir una función de agregación.
Ejemplos con una sola condición
Clientes con pagos totales superiores a 100
SELECT customer_id, SUM(amount) AS total_paid
FROM payment
GROUP BY customer_id
HAVING SUM(amount) > 100;
Resultado: solo los clientes cuyos pagos totales superan 100.
Empleados que han procesado más de 50 pagos
SELECT staff_id, COUNT(*) AS payments_count
FROM payment
GROUP BY staff_id
HAVING COUNT(*) > 50;
Resultado: los empleados con más de 50 pagos procesados.
Clientes con un pago medio ≥ 5
SELECT customer_id, AVG(amount) AS avg_payment
FROM payment
GROUP BY customer_id
HAVING AVG(amount) >= 5;
Resultado: los clientes cuyo pago medio es de al menos 5.
HAVING con varias condiciones
Puedes combinar condiciones con AND y OR:
SELECT staff_id, COUNT(*) AS cnt, SUM(amount) AS total
FROM payment
GROUP BY staff_id
HAVING COUNT(*) > 50 AND SUM(amount) > 500;
Resultado: los empleados con más de 50 pagos Y un total superior a 500.
Con el operador OR
SELECT customer_id, COUNT(*) AS rentals, SUM(amount) AS paid
FROM payment
GROUP BY customer_id
HAVING COUNT(*) > 100 OR SUM(amount) > 1000;
Resultado: los clientes con más de 100 pagos O un total superior a 1000.
Ejemplos prácticos
Categorías de películas con ventas superiores a 2000
SELECT category_id, SUM(p.amount) AS total_sales
FROM payment p
JOIN rental r ON p.rental_id = r.rental_id
JOIN inventory i ON r.inventory_id = i.inventory_id
JOIN film_category fc ON i.film_id = fc.film_id
GROUP BY category_id
HAVING SUM(p.amount) > 2000;
Países con más de 20 clientes
SELECT country, COUNT(*) AS customers_count
FROM customer cu
JOIN address a ON cu.address_id = a.address_id
JOIN city ci ON a.city_id = ci.city_id
JOIN country co ON ci.country_id = co.country_id
GROUP BY country
HAVING COUNT(*) > 20;
Empleados con ingresos diarios superiores a 500
SELECT staff_id, DATE(payment_date) AS pay_date, SUM(amount) AS daily_revenue
FROM payment
GROUP BY staff_id, DATE(payment_date)
HAVING SUM(amount) > 500;
Resultado: 56 filas, cada par empleado-día en que el empleado cobró más de 500.
Preguntas frecuentes
¿Por qué no puedo usar WHERE en lugar de HAVING?
WHERE actúa antes de agrupar, así que no puede comprobar funciones de agregación. HAVING actúa después de agrupar y puede analizar los resultados de la agregación (COUNT, SUM, AVG, etc.).
¿Puedo usar una columna no agregada en HAVING?
Sí, puedes usar una columna de GROUP BY, pero normalmente no hace falta. Por ejemplo, HAVING customer_id > 100 funciona, pero es más natural escribirlo en WHERE, antes de agrupar.
¿Se puede usar HAVING sin GROUP BY?
Técnicamente, en algunos SGBD es posible, pero es poco práctico, porque HAVING está pensado para filtrar grupos. Usa WHERE para filtrar filas individuales sin agrupar.
Preguntas de entrevista
¿Qué es HAVING y en qué se diferencia de WHERE?
HAVING filtra grupos después de agregar, mientras que WHERE filtra filas antes de agrupar. WHERE no puede trabajar con funciones de agregación, mientras que HAVING trabaja precisamente con ellas.
¿Puedo usar WHERE y HAVING en la misma consulta?
Sí, e incluso se recomienda. WHERE filtra filas antes de agrupar y HAVING filtra grupos después. Por ejemplo, WHERE amount > 10 GROUP BY customer_id HAVING SUM(amount) > 100 primero excluye los pagos pequeños, después agrupa y luego filtra los grupos.
¿Cuál es el orden de ejecución: WHERE o HAVING?
Primero se aplica WHERE (antes de GROUP BY), después GROUP BY agrupa, luego HAVING filtra los grupos resultantes y, por último, se aplican ORDER BY y LIMIT.
Puntos clave de esta lección:
HAVINGfiltra grupos después de agregar;WHEREfiltra filas antes de agrupar.HAVINGse usa con funciones de agregación (COUNT, SUM, AVG, MIN, MAX).- Puedes combinar varias condiciones en
HAVINGconAND/OR. - A menudo WHERE y HAVING trabajan juntos: WHERE excluye las filas que sobran y HAVING filtra los grupos.
HAVINGpermite consultas analíticas profundas con filtrado a nivel de grupo.