Lesión 4.3 · Tiempo de lectura: ~7 minutos
Al usar GROUP BY con agregados, a menudo necesitas filtrar grupos por sus resultados agregados. HAVING es el operador para filtrar grupos, así como WHERE filtra filas individuales. En esta lección, aprenderás las diferencias entre WHERE y HAVING, la sintaxis y ejemplos prácticos en Sakila. Al final, usarás HAVING con confianza para un análisis de datos profundo.
Filtrado de Grupos con HAVING
En lecciones anteriores, aprendiste GROUP BY para agrupar datos y aplicar agregados. Ahora viene el siguiente paso: filtrar los grupos mismos por condiciones sobre valores agregados.
HAVING hace esto permitiendo condiciones después de la agrupación.
WHERE vs HAVING
- WHERE filtra filas antes de agrupar
- HAVING filtra grupos después de la agregación
SELECT column1, COUNT(*) AS cnt
FROM table
WHERE column1 > 100 -- filtrar ANTES de agrupar
GROUP BY column1
HAVING COUNT(*) > 10; -- filtrar DESPUÉS de agrupar
Sintaxis de HAVING
Estructura básica:
SELECT column1, AGG_FUNCTION(column2)
FROM table
GROUP BY column1
HAVING condition;
La condición en HAVING típicamente involucra una función agregada.
Ejemplos con Condición Única
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 clientes cuyos pagos totales superan 100.
Miembros del personal que procesaron más de 50 pagos
SELECT staff_id, COUNT(*) AS payments_count
FROM payment
GROUP BY staff_id
HAVING COUNT(*) > 50;
Resultado: personal con más de 50 pagos procesados.
Clientes con pago promedio ≥ 5
SELECT customer_id, AVG(amount) AS avg_payment
FROM payment
GROUP BY customer_id
HAVING AVG(amount) >= 5;
Resultado: clientes cuyo pago promedio es al menos 5.
HAVING con Múltiples Condiciones
Puedes combinar condiciones usando 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: personal con más de 50 pagos Y total superior a 500.
Con 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: clientes con más de 100 pagos O 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;
Tiendas con ingresos diarios superiores a 500
SELECT store_id, DATE(payment_date) AS pay_date, SUM(amount) AS daily_revenue
FROM payment
GROUP BY store_id, DATE(payment_date)
HAVING SUM(amount) > 500;
Preguntas Frecuentes
¿Por qué no puedo usar WHERE en lugar de HAVING?
WHERE opera antes de agrupar, por lo que no puede verificar funciones agregadas. HAVING opera después de agrupar y puede analizar resultados de agregación (COUNT, SUM, AVG, etc.).
¿Puedo usar una columna no agregada en HAVING?
Sí, puedes usar una columna de GROUP BY, pero generalmente esto no es necesario. Por ejemplo, HAVING customer_id > 100 funciona, pero es más natural escribir esto en WHERE antes de agrupar.
¿Se puede usar HAVING sin GROUP BY?
Técnicamente en algunos SGBD esto es posible, pero es impráctico ya que HAVING está diseñado para filtrar grupos. Usa WHERE para filtrar filas individuales sin agrupar.
Preguntas de Entrevista
¿Qué es HAVING y cómo se diferencia de WHERE?
HAVING filtra grupos después de la agregación, mientras que WHERE filtra filas antes de agrupar. WHERE no puede trabajar con funciones agregadas, pero HAVING solo puede trabajar con ellas.
¿Puedo usar tanto WHERE como HAVING en una consulta?
Sí, esto es incluso recomendable. 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 pagos pequeños, luego agrupa y filtra grupos.
¿Cuál es el orden de ejecución: WHERE o HAVING?
WHERE se aplica primero (antes de GROUP BY), luego GROUP BY realiza la agrupación, luego HAVING filtra los grupos resultantes, y finalmente se aplican ORDER BY y LIMIT.
Puntos clave de esta lección:
HAVINGfiltra grupos después de la agregación,WHEREfiltra filas antes de agrupar.HAVINGse usa con funciones agregadas (COUNT, SUM, AVG, MIN, MAX).- Puedes combinar múltiples condiciones en
HAVINGusandoAND/OR. - A menudo WHERE y HAVING trabajan juntos: WHERE excluye filas no deseadas, HAVING filtra grupos.
HAVINGpermite consultas analíticas profundas con filtrado a nivel de grupo.
En la próxima lección, exploraremos ORDER BY para ordenar resultados.