HAVING en SQL: directo al punto
Usamos HAVING cuando queremos filtrar por un resultado agregado, por ejemplo:
- Clientes con más de 2 compras.
- Productos vendidos más de 10 veces.
- Categorías con ventas mayores a 1000.
- Materias con promedio mayor o igual a 6.
La forma base es:
SELECT columna, FUNCION_AGREGADA(columna)
FROM tabla
GROUP BY columna
HAVING condicion_sobre_el_grupo;
Tabla de ejemplo
CREATE TABLE Ventas (
Id INT PRIMARY KEY,
Cliente VARCHAR(50),
Categoria VARCHAR(50),
Cantidad INT,
PrecioUnitario DECIMAL(10, 2)
);
INSERT INTO Ventas (Id, Cliente, Categoria, Cantidad, PrecioUnitario) VALUES
(1, 'Ana', 'Cursos', 1, 1200.00),
(2, 'Bruno', 'Cursos', 1, 1500.00),
(3, 'Ana', 'Libros', 2, 300.00),
(4, 'Carla', 'Cursos', 1, 1200.00),
(5, 'Bruno', 'Libros', 3, 250.00),
(6, 'Ana', 'Cursos', 1, 1800.00);
1. HAVING con COUNT
Queremos ver clientes que tienen más de una venta.
SELECT
Cliente,
COUNT(*) AS TotalVentas
FROM Ventas
GROUP BY Cliente
HAVING COUNT(*) > 1;
Qué hace:
- Agrupa las ventas por cliente.
- Cuenta cuántas ventas tiene cada cliente.
- Deja solo los clientes con más de una venta.
2. HAVING con SUM
Queremos ver clientes que gastaron más de 1500.
SELECT
Cliente,
SUM(Cantidad * PrecioUnitario) AS TotalGastado
FROM Ventas
GROUP BY Cliente
HAVING SUM(Cantidad * PrecioUnitario) > 1500;
Este caso es muy común en reportes: primero calculás el total por cliente y después filtrás por ese total.
3. HAVING con AVG
Supongamos una tabla de notas:
CREATE TABLE Notas (
Id INT PRIMARY KEY,
Alumno VARCHAR(50),
Materia VARCHAR(50),
Nota DECIMAL(4, 2)
);
Queremos materias con promedio aprobado.
SELECT
Materia,
AVG(Nota) AS Promedio
FROM Notas
GROUP BY Materia
HAVING AVG(Nota) >= 6;
AVG(Nota) calcula el promedio por materia. HAVING deja solo las materias cuyo promedio cumple la condición.
WHERE vs HAVING
Esta es la diferencia más importante:
| Cláusula | Cuándo filtra | Ejemplo |
|---|---|---|
WHERE | Antes de agrupar | Ventas de la categoría Cursos |
HAVING | Después de agrupar | Clientes con total mayor a 1500 |
Ejemplo usando los dos:
SELECT
Cliente,
SUM(Cantidad * PrecioUnitario) AS TotalCursos
FROM Ventas
WHERE Categoria = 'Cursos'
GROUP BY Cliente
HAVING SUM(Cantidad * PrecioUnitario) > 1500;
Qué pasa ahí:
WHERE Categoria = 'Cursos'deja solo ventas de cursos.GROUP BY Clienteagrupa esas ventas por cliente.HAVING SUM(...) > 1500filtra clientes cuyo total en cursos supera 1500.
Ejemplo clásico: duplicados
Encontrar emails repetidos:
SELECT
Email,
COUNT(*) AS Cantidad
FROM Personas
GROUP BY Email
HAVING COUNT(*) > 1;
Este patrón aparece muchísimo en ejercicios:
- Agrupar por el campo que puede repetirse.
- Contar cuántas veces aparece.
- Filtrar con
HAVING COUNT(*) > 1.
Resumen rápido
| Necesito | Uso |
|---|---|
| Filtrar filas normales | WHERE |
| Filtrar grupos calculados | HAVING |
| Detectar duplicados | GROUP BY campo HAVING COUNT(*) > 1 |
| Filtrar totales | HAVING SUM(...) > valor |
| Filtrar promedios | HAVING AVG(...) >= valor |
Si la condición depende de una función agregada, casi seguro va en HAVING.