HAVING en SQL: qué es, cómo se usa y ejemplos prácticos

En SQL, la cláusula HAVING se utiliza para filtrar los resultados de un GROUP BY, es decir, aplicar condiciones sobre grupos en lugar de sobre filas individuales.

Mientras que WHERE filtra filas antes de agrupar, HAVING actúa después de que las filas ya han sido agrupadas y se han calculado funciones de agregación como SUM(), COUNT(), AVG(), MAX() o MIN().

👉 Si pensás en HAVING como el “WHERE de los grupos”, nunca más te vas a confundir.

Sintaxis básica de HAVING

SELECT columna1, funcion_agregada(columna2)
FROM tabla
WHERE condiciones_filas
GROUP BY columna1
HAVING condiciones_grupo
ORDER BY columna1;
  • WHERE: filtra filas individuales.
  • GROUP BY: agrupa filas por columnas.
  • HAVING: filtra los grupos resultantes.
  • ORDER BY: ordena la salida final.

Ejemplos prácticos de HAVING

1) Clientes con más de 5 pedidos

SELECT cliente_id, COUNT(*) AS total_pedidos
FROM pedidos
GROUP BY cliente_id
HAVING COUNT(*) > 5;

👉 Devuelve solo los clientes que tienen más de 5 pedidos.

2) Departamentos con salario promedio mayor a 3000

SELECT departamento, AVG(salario) AS salario_promedio
FROM empleados
GROUP BY departamento
HAVING AVG(salario) > 3000;

👉 Filtra únicamente los departamentos con sueldos altos.

3) Países con más de 100 clientes activos

SELECT pais, COUNT(*) AS clientes_activos
FROM clientes
WHERE activo = 1
GROUP BY pais
HAVING COUNT(*) > 100;

👉 Primero se filtran solo clientes activos (WHERE). Luego, HAVING se encarga de mostrar países con más de 100.

4) Productos con ventas superiores a 10.000

SELECT producto_id, SUM(total) AS ventas
FROM pedidos
GROUP BY producto_id
HAVING SUM(total) > 10000;

5) Varias condiciones en HAVING

SELECT departamento, COUNT(*) empleados, AVG(salario) promedio
FROM empleados
GROUP BY departamento
HAVING COUNT(*) > 10 AND AVG(salario) > 2500;

👉 Devuelve departamentos con más de 10 empleados y salario medio superior a 2500.

Diferencias clave: WHERE vs HAVING

CaracterísticaWHEREHAVING
MomentoAntes de agruparDespués de agrupar
Se aplica aFilas individualesGrupos de filas
Admite agregados❌ No✅ Sí
EjemploWHERE salario > 2000HAVING AVG(salario) > 2000

👉 Regla práctica:

  • Si filtrás filas, usá WHERE.
  • Si filtrás resultados de agregaciones, usá HAVING.

HAVING sin GROUP BY

En la mayoría de motores se puede usar HAVING incluso sin GROUP BY, actuando como un filtro de toda la tabla tratada como un único grupo.

Ejemplo:

SELECT SUM(total) AS ventas_totales
FROM pedidos
HAVING SUM(total) > 50000;

👉 Devuelve el total de ventas solo si supera 50.000.

Errores comunes con HAVING

  1. Usar HAVING cuando corresponde WHERE
-- ❌ Mal: HAVING usado para filtrar filas
SELECT * FROM empleados
GROUP BY departamento
HAVING salario > 2000;

👉 Error, porque salario no está en función agregada ni en GROUP BY.
✅ Solución:

SELECT * FROM empleados
WHERE salario > 2000;
  1. Olvidar agrupar todas las columnas
-- ❌ Error en motores estrictos
SELECT departamento, nombre, COUNT(*)
FROM empleados
GROUP BY departamento
HAVING COUNT(*) > 5;

👉 nombre no está ni en GROUP BY ni en una función de agregación.

  1. Confundir COUNT(*) con COUNT(columna)
  • COUNT(*): cuenta todas las filas del grupo.
  • COUNT(columna): ignora filas con NULL en esa columna.
  1. Creer que HAVING mejora performance
    👉 En realidad, el filtrado en HAVING se hace después del GROUP BY, cuando ya se procesó todo. Si podés aplicar filtros previos, usá WHERE para reducir filas antes.

Buenas prácticas con HAVING

  • Filtrar primero lo que puedas con WHERE.
  • Usar alias para funciones agregadas y reutilizarlos en HAVING (en motores que lo soportan).
  • Combinar condiciones con AND / OR para expresiones complejas.
  • Evitar agrupar más columnas de las necesarias: cada columna extra aumenta la cardinalidad del GROUP BY.
  • Usar HAVING para métricas de negocio: top clientes, ventas mínimas, umbrales.

Ejemplo avanzado: top clientes por región

SELECT c.region, c.nombre, SUM(p.total) AS ventas
FROM clientes c
JOIN pedidos p ON p.cliente_id = c.id
WHERE p.fecha >= '2025-01-01'
GROUP BY c.region, c.nombre
HAVING SUM(p.total) > 1000
ORDER BY c.region, ventas DESC;

👉 Devuelve clientes que superaron los 1000 en ventas durante 2025, agrupados por región.

HAVING con ROLLUP y CUBE

Cuando usás funciones avanzadas de agrupación, HAVING también sirve para filtrar los subtotales.

Ejemplo en MySQL con ROLLUP:

SELECT departamento, puesto, SUM(salario) total
FROM empleados
GROUP BY departamento, puesto WITH ROLLUP
HAVING SUM(salario) > 10000;

👉 Solo muestra grupos y subtotales cuyo total supere 10.000.

Preguntas frecuentes (FAQ)

1. ¿HAVING siempre necesita GROUP BY?
No. Si no hay GROUP BY, toda la tabla se trata como un grupo único.

2. ¿Puedo usar columnas no agregadas en HAVING?
Depende del motor. En general, sí si están también en el GROUP BY.

3. ¿HAVING reemplaza WHERE?
No. Son complementarios. Usá WHERE para filas, HAVING para grupos.

4. ¿HAVING afecta performance?
Sí: se evalúa después del GROUP BY. Si podés filtrar antes con WHERE, es más eficiente.

5. ¿HAVING puede usarse con múltiples funciones de agregación?
Sí, y podés combinarlas con operadores lógicos (AND, OR).

Conclusión

La cláusula HAVING en SQL es la forma estándar de filtrar resultados agrupados después de aplicar funciones de agregación. Es esencial en reportes de negocio y análisis de datos, porque permite trabajar con métricas y aplicar condiciones sobre ellas.

La clave está en entender la diferencia con WHERE:

  • WHERE → filas.
  • HAVING → grupos.

Dominar HAVING junto con GROUP BY te permitirá crear consultas más potentes y profesionales.

Profundiza en filtros sobre agregados en GROUP BY y HAVING y vuelve al Glosario SQL completo.

Scroll al inicio