⏳ ¡Últimos días de octubre! SQLtest.online es gratuito gracias a las donaciones, y aún necesitamos alcanzar la meta de este mes para que el sitio siga funcionando en noviembre. Cada donación cuenta. Apoyar ahora →
Código SQL copiado al portapapeles

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.

SQL HAVING y WHERE: WHERE filtra filas antes de agrupar, HAVING filtra grupos después; HAVING SUM(amount) width= 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:

  • HAVING filtra grupos después de agregar; WHERE filtra filas antes de agrupar.
  • HAVING se usa con funciones de agregación (COUNT, SUM, AVG, MIN, MAX).
  • Puedes combinar varias condiciones en HAVING con AND/OR.
  • A menudo WHERE y HAVING trabajan juntos: WHERE excluye las filas que sobran y HAVING filtra los grupos.
  • HAVING permite consultas analíticas profundas con filtrado a nivel de grupo.

Intenta resolver las siguientes tareas para reforzar lo que aprendiste en esta lección.

  1. Nombres de Actores Duplicados
  2. Categorías de Películas con Larga Duración Promedio
  3. ¿Cuál es la diferencia entre HAVING y WHERE?
  4. Apellidos de Actores Duplicados
  5. Películas Más Retrasadas