Hay algo que todavía no hemos comentado, y es ¿cómo filtrar los grupos después de aplicar agregados? A veces no necesitamos todas las facultades — solo las que tienen más de cien estudiantes. O queremos ver solo los departamentos donde el salario medio es mayor de 50.000. Hoy vamos a conocer el filtrado de datos agregados usando HAVING.
¿Para qué necesitamos HAVING si ya tenemos WHERE? ¿No podríamos poner WHERE después de GROUP BY? :)
¡No es tan simple! Primero, el orden de los operadores en SQL está fijado y WHERE se ejecuta antes que GROUP BY.
¿Y si intentamos ponerlo después de GROUP BY?
Tampoco se puede. Muy a menudo necesitamos filtrar filas de la tabla antes de agrupar. Luego hacemos la agrupación sobre los datos filtrados. Y después descartamos algunos datos innecesarios tras la agrupación.
Entonces, ¿por qué no tomar el operador WHERE, copiarlo, llamarlo HAVING y ponerlo después de GROUP BY?
¡Pues sí, eso es justo lo que hacemos! :)
Diferencia entre HAVING y WHERE
WHERE filtra filas antes de la agrupación.
Imagina que seleccionas tartas por sabor: las de fresa y chocolate las dejas, el resto fuera. Eso es tarea de WHERE.
HAVING filtra después de que los datos han sido agrupados y las funciones agregadas han hecho su magia.
Por ejemplo, ya agrupaste las tartas por mesa, contaste cuántas hay y ahora quieres dejar solo las mesas donde hay más de tres tartas.
Así que HAVING se usa para filtrar datos a nivel de grupo.
Sintaxis de HAVING
La sintaxis es casi igual que la de WHERE, pero funciona un poco diferente:
SELECT columnas, funciones_agregadas
FROM tabla
GROUP BY columnas
HAVING condición;
Etapas de ejecución:
- Primero las filas se filtran con
WHERE. - Luego los datos se agrupan usando
GROUP BY. - Se aplican funciones agregadas a los resultados de la agrupación.
- Finalmente, el resultado se filtra usando
HAVING.
Ejemplos de uso de HAVING
Ejemplo 1: Filtrar facultades con muchos estudiantes
Quieres saber qué facultades en la universidad tienen más de 100 estudiantes. Supón que tenemos la tabla students:
| id | name | faculty |
|---|---|---|
| 1 | Alice | Engineering |
| 2 | Bob | Engineering |
| 3 | Charlie | Arts |
| 4 | Daisy | Business |
| 5 | ... | ... |
Consulta:
SELECT faculty, COUNT(*) AS student_count
FROM students
GROUP BY faculty
HAVING COUNT(*) > 100;
¿Qué pasa aquí?
- Primero agrupamos los estudiantes por la columna
facultyusandoGROUP BY. - Luego la función agregada
COUNT(*)cuenta cuántos estudiantes hay en cada facultad. - Por último,
HAVINGdescarta todas las facultades donde hay 100 estudiantes o menos.
Resultado:
| faculty | student_count |
|---|---|
| Engineering | 150 |
| Arts | 120 |
Ejemplo 2: Departamentos con salario medio alto
Quieres encontrar solo los departamentos donde el salario medio de los empleados supera los 50.000. Supón que tenemos la tabla employees:
| id | name | department | salary |
|---|---|---|---|
| 1 | Alice | IT | 60000 |
| 2 | Bob | HR | 45000 |
| 3 | Charlie | IT | 70000 |
| 4 | Daisy | HR | 52000 |
| 5 | ... | ... | ... |
Consulta:
SELECT department, AVG(salary) AS avg_salary
FROM employees
GROUP BY department
HAVING AVG(salary) > 50000;
Resultado:
| department | avg_salary |
|---|---|
| IT | 65000 |
Ojo: HAVING trabaja con los resultados que se han calculado después de GROUP BY.
Orden de ejecución de WHERE, GROUP BY y HAVING
El filtrado con WHERE y HAVING ocurre en diferentes etapas. Para entender mejor la diferencia, vamos a ver el proceso paso a paso de una consulta:
WHERE: filtrado de filas.En esta etapa se procesan todas las filas de la tabla. Si una fila no cumple la condición de
WHERE, ni siquiera pasa a la siguiente fase.GROUP BY: agrupación de filas.Después del filtrado, las filas se agrupan según las columnas indicadas en
GROUP BY.Funciones agregadas:
Se aplican funciones agregadas como
COUNT(),AVG(),SUM(), etc. a los datos agrupados.HAVING: filtrado de grupos.En esta etapa solo se procesan los resultados de los agregados. Las condiciones de
HAVINGse aplican solo a los grupos.
Particularidades de HAVING
Particularidad 1: Trabajar con agregados
La diferencia principal de HAVING respecto a WHERE es que trabaja con funciones agregadas. Por ejemplo:
SELECT department, AVG(salary)
FROM employees
GROUP BY department
HAVING AVG(salary) > 50000;
En esta consulta AVG(salary) no se puede usar dentro de WHERE, porque WHERE procesa filas antes de la agrupación. Una consulta como:
SELECT department, AVG(salary)
FROM employees
WHERE AVG(salary) > 50000
GROUP BY department;
provocará un error: aggregate functions are not allowed in WHERE.
Particularidad 2: Filtrar sin agrupación
Puedes usar HAVING incluso sin un GROUP BY explícito. En ese caso la consulta se interpreta como si hubiera un solo grupo — todos los registros:
SELECT AVG(salary) AS avg_salary
FROM employees
HAVING AVG(salary) > 50000;
Ejemplo práctico
Supón que tenemos una tienda y una tabla de ventas sales:
| id | product_id | sales_amount |
|---|---|---|
| 1 | 101 | 200.00 |
| 2 | 102 | 300.00 |
| 3 | 101 | 400.00 |
| 4 | 103 | 150.00 |
Consulta: encontrar productos con un volumen total de ventas mayor de 500.
SELECT product_id, SUM(sales_amount) AS total_sales
FROM sales
GROUP BY product_id
HAVING SUM(sales_amount) > 500;
Resultado:
| product_id | total_sales |
|---|---|
| 101 | 600.00 |
Errores típicos
Uso de agregados en WHERE:
Por ejemplo:
SELECT department, AVG(salary)
FROM employees
WHERE AVG(salary) > 50000
GROUP BY department;
Error: no se pueden usar funciones agregadas en WHERE.
Errores con NULL:
Si los datos contienen NULL, el filtrado puede dar resultados inesperados. Por ejemplo:
SELECT department, SUM(salary)
FROM employees
GROUP BY department
HAVING SUM(salary) > 0;
Si la columna salary solo contiene NULL, el resultado puede ser cero o vacío.
¡Enhorabuena! A este nivel ya puedes filtrar datos agregados con confianza. Recuerda que HAVING es tu llave para el análisis a nivel de grupos, donde WHERE ya no es suficiente.
GO TO FULL VERSION