Saltar al contenido principal
SQL y analíticaLección interactiva5 min de lectura

WHERE vs HAVING en SQL: cuándo filtrar antes y cuándo después de agrupar

Por Pedro RodríguezPublicado Actualizado

Escribes WHERE COUNT(*) >= 2 y SQL te responde con un error. Cambias WHERE por HAVING y funciona. Parece una regla arbitraria, pero tiene una razón: los dos filtran en momentos distintos de la consulta. Aquí lo ves con ejemplos que se ejecutan, con una base de ejemplo del blog.

¿En qué orden ejecuta SQL una consulta?

El orden en que escribes una consulta no es el orden en que SQL la resuelve. Este es el orden lógico:

PasoCláusulaQué hace
1FROM y JOINArma el conjunto de filas de partida
2WHEREDescarta filas individuales
3GROUP BYAgrupa las filas que quedaron
4HAVINGDescarta grupos completos
5SELECTCalcula las columnas que se devuelven
6ORDER BY y LIMITOrdena y recorta

Ahí está la razón de todo: cuando corre WHERE, los grupos todavía no existen, así que no hay un COUNT por grupo contra el cual comparar. HAVING corre después de agrupar, cuando ya hay un conteo por grupo.

Primero, los datos

La base de ejemplo tiene 14 pedidos. Cuántos hay por estado:

base: E-commerce (base de ejemplo del blog) · Ctrl + Enter para ejecutar
El resultado aparece aquí.

Hay 3 cancelados y 11 completados. Vamos a trabajar con los completados.

WHERE: filtra filas antes de agrupar

Cuenta los pedidos completados de cada cliente. El WHERE descarta primero los cancelados, y recién después se agrupa:

base: E-commerce (base de ejemplo del blog) · Ctrl + Enter para ejecutar
El resultado aparece aquí.

Salen 7 grupos. El primero tiene customer_id en NULL: es el pedido 114, que se registró sin cliente. GROUP BY trata a los NULL como un grupo propio.

HAVING: filtra grupos después de agrupar

Ahora queremos solo los clientes con al menos 2 pedidos completados. Esa condición habla del resultado de COUNT(*), no de una fila, así que va en HAVING:

base: E-commerce (base de ejemplo del blog) · Ctrl + Enter para ejecutar
El resultado aparece aquí.

Quedan los clientes 1, 3 y 8, con 3, 2 y 2 pedidos. Los demás grupos de la celda anterior se descartaron completos.

¿Por qué da error si uso COUNT en el WHERE?

Si intentas lo mismo con WHERE:

SELECT customer_id, COUNT(*) AS pedidos
FROM orders
WHERE status = 'completada' AND COUNT(*) >= 2
GROUP BY customer_id;

SQLite responde misuse of aggregate: COUNT(). Otros motores usan mensajes distintos, pero el motivo es el mismo: en el paso del WHERE todavía no hay grupos, así que COUNT(*) no tiene sentido ahí.

HAVING con SUM y la trampa de los NULL

HAVING funciona con cualquier agregado. Veamos los clientes que gastaron más de 200 en pedidos completados:

base: E-commerce (base de ejemplo del blog) · Ctrl + Enter para ejecutar
El resultado aparece aquí.

Salen los clientes 1 y 3, con 400 cada uno. Hay un detalle: el cliente 6 tiene un pedido completado, pero su total_amount es NULL, así que su SUM es NULL, y NULL > 200 no es verdadero. Ese grupo queda fuera sin avisar. Si los NULL importan en tu análisis, revísalos antes de filtrar.

¿Puedo usar WHERE y HAVING en la misma consulta?

Sí, y es lo habitual: WHERE para las condiciones sobre filas y HAVING para las condiciones sobre grupos. Cada uno hace su trabajo:

base: E-commerce (base de ejemplo del blog) · Ctrl + Enter para ejecutar
El resultado aparece aquí.

El WHERE quita los pedidos cancelados y el pedido sin cliente. El HAVING deja solo a quienes tienen al menos 2 pedidos y más de 300 en total.

¿Cuándo uso WHERE y cuándo HAVING?

Tu condición habla de...Usa
Una columna de cada fila (status, country, order_date)WHERE
Un resultado agregado (COUNT, SUM, AVG, MAX)HAVING
Ambas cosasWHERE para las filas y HAVING para los grupos

Una regla útil: si una condición se puede poner en el WHERE, ponla ahí. Filtrar filas antes de agrupar suele dejar menos datos para procesar y hace la consulta más clara.

¿Qué te preguntan sobre esto en una entrevista de SQL?

La pregunta típica es "¿cuál es la diferencia entre WHERE y HAVING?". La respuesta corta que busca el entrevistador es el orden de ejecución: WHERE va antes de agrupar y no admite agregados, HAVING va después y sí. Si además das un ejemplo de los dos juntos, como el de la celda 5, ya respondiste mejor que la mayoría.

Inténtalo tú mismo

Escribe una consulta que muestre el nombre de los clientes que gastaron más de 150 en pedidos completados, junto con ese total. Llama total a la columna del gasto y ordena por nombre.

base: E-commerce (base de ejemplo del blog) · Ctrl + Enter para ejecutar
El resultado aparece aquí.

FUENTES Y VERIFICACIÓN

Todas las consultas de este artículo se ejecutaron contra la base de ejemplo del blog antes de publicarse. Referencias: documentación oficial de SQLite sobre SELECT (cláusulas WHERE, GROUP BY y HAVING) y sobre funciones de agregado; estándar SQL, orden lógico de evaluación de una consulta. Revisado por Pedro Rodríguez. Se revisa cada trimestre.

Únete a la comunidad de The Analyst Hub

Deja tu correo y te llega la invitación al Discord y el newsletter semanal con lo nuevo en datos e IA.

Solo lo usamos para el enlace al Discord y el newsletter. Puedes darte de baja cuando quieras.

WHERE vs HAVING en SQL | The Analyst Hub