Curso
WHERE y HAVING son dos cláusulas esenciales en SQL. Tanto si escribes consultas superavanzadas como si son muy sencillas, te encontrarás con la necesidad de utilizar ambas. Puedes pensar en WHERE y HAVING como hermanos. Ambos cumplen una función similar (filtrar), y a menudo aparecen juntos. Pero, al igual que los hermanos, tienen características distintas y papeles únicos.
Si estás en proceso de clasificar WHERE y HAVING, te sugiero que te inscribas en nuestro curso de habilidades SQL Fundamentals como punto de partida excelente y completo. Te enseñará las diferentes cláusulas SQL, el orden de ejecución SQL, la optimización de las consultas SQL y muchas otras cosas fundamentales.
La respuesta breve: DÓNDE vs. TENIENDO
La respuesta breve y fuente de confusión para mucha gente es que WHERE trabaja con datos a nivel de fila, mientras que HAVING opera con datos agrupados. He aquí una pauta:
-
WHEREfiltra las filas antes de que se produzca cualquier agrupación o agregación. Se aplica a filas individuales y no puede utilizarse con funciones agregadas. -
HAVINGfiltra los grupos después de haber realizado la agrupación y la agregación. Se aplica a los resultados de las funciones agregadas y se utiliza en combinación conGROUP BY.
Un ejemplo rápido para mostrar la diferencia
Veamos un ejemplo rápido. Si quieres seguir tu propio flujo de trabajo, puedes descargar el conjunto de datos de alquiler de propiedades de este repositorio de GitHub.
Ahora, supongamos que necesitamos devolver todas las propiedades de nuestro conjunto de datos que tengan un precio de alquiler inferior a 500 $. El nivel de detalle de cada fila del conjunto de datos (una propiedad por fila) coincide con el nivel de detalle de la condición de la consulta. Por lo tanto, utilizamos WHERE en la siguiente consulta:
SELECT *
FROM rentals
WHERE rental_price < 500
El resultado sería el siguiente. Observa que se devuelven 118 filas.

Filtrado simple de filas con WHERE. Imagen del autor.
Ahora, supongamos que no queremos tener una tabla de inmuebles, sino de ciudades que tienen un precio medio de alquiler inferior a 2.700 $. En lugar de que cada fila corresponda a un inmueble, agruparemos las filas y agregaremos el precio de alquiler en un precio medio de alquiler para cada ciudad. Por lo tanto, utilizaremos HAVING, como en esta consulta:
SELECT city, AVG(rental_price) AS average_rent
FROM rentals
GROUP BY city
HAVING AVG(rental_price) < 2700;
Y el resultado sería Observa que sólo hay un resultado.

Filtrado simple de grupos con HAVING. Imagen del autor.
WHERE, HAVING y orden de ejecución SQL
Vemos que WHERE funciona con filtrado a nivel de filas, mientras que HAVING funciona con filtrado a nivel de agregados. Comprender esta diferencia también nos allana el camino para conocer el orden de ejecución de las cláusulas de SQL.
WHERE se evalúa antes de GROUP BY, y justo después de FROM (y JOIN si está presente); no puede ocuparse de ninguna agrupación o agregación. WHERE entra en juego antes de que se realice ninguna agregación. Por eso sólo funciona con datos a nivel de fila.
Por su parte, HAVING viene después de ejecutar la cláusula GROUP BY. Eso significa que entra en juego después de transformar la tabla y agruparla a un nivel distinto del nivel de granularidad de la tabla de origen. HAVING opera sobre la nueva versión transformada de la tabla.
Cómo utilizar la cláusula WHERE en SQL
Demos un paso atrás y analicemos cada cláusula por separado. Podemos empezar con la cláusula WHERE.
Sintaxis y sentencias WHERE
WHERE puede utilizarse en tres sentencias SQL diferentes: SELECT, UPDATE, y DELETE.
WHERE en sentencias SELECT
En las sentencias SELECT, que son las que se utilizan para obtener datos de la base de datos, WHERE desempeña su papel directo en el filtrado a nivel de filas y tiene su lugar bien conocido justo después de la cláusula FROM, como podemos ver en la siguiente consulta:
SELECT column1, column2… etc.
FROM table_name
WHERE condition;
WHERE utilizado con SELECT es el lugar donde la cláusula WHERE se confunde más a menudo con HAVING.
WHERE en las sentencias UPDATE
Además, WHERE desempeña un papel importante en las sentencias UPDATE para señalar la fila en la que debe producirse la actualización de los datos, como podemos ver con la siguiente sintaxis:
UPDATE table_name
SET column_name1 = value1, column_name2 = value2… etc.
WHERE condition;
WHERE en las sentencias DELETE
WHERE también es un complemento útil de las sentencias DELETE para señalar los registros (filas) que deben eliminarse, como podemos ver aquí:
DELETE FROM table_name
WHERE condition;
Cómo escribir condiciones WHERE
WHERE se escriben como una simple expresión lógica. Consta de tres partes: la variable/operando, la condición y el valor/resultado. Echemos un vistazo a las opciones de las condiciones de WHERE, que incluyen operadores de comparación y lógicos.
| Signo de operador | Descripción | Tipo de datos del operando |
|---|---|---|
| = | Igual a (en la fecha) | Numérico, Texto, Fecha/hora, Booleano |
| < | Menos de (antes de la fecha) | Numérico, Fecha/hora |
| > | Mayor que (después de la fecha) | Numérico, Fecha/hora |
| <= | Inferior o igual a (en la fecha o antes) | Numérico, Fecha/hora |
| >= | Mayor o igual que (en o después de la fecha) | Numérico, Fecha/hora |
| <> (!=) | No igual a (no en la fecha) | Numérico, Texto, Fecha/hora, Booleano |
| IN | Igual a más de un valor (en varias fechas) | Numérico, Texto, Fecha/hora, Booleano (¡sin sentido!) |
| COMO | Coincide con un patrón de texto (utilizando comodines) | Texto |
| ENTRE | Existe en una gama | Numérico, Fecha/hora |
| Y | Combina varias condiciones, todas deben ser verdaderas | Lógico (booleano) |
| O | Combina varias condiciones, al menos una debe ser verdadera | Lógico (booleano) |
| NO | Niega una condición | Lógico (booleano) |
| IS NULL | Comprueba si hay valores nulos | Todos los tipos de datos |
| NO ES NULO | Comprueba los valores no nulos | Todos los tipos de datos |
He aquí un ejemplo en el que utilizamos NOT junto con el operador de comparación IN:
SELECT *
FROM rentals
WHERE city NOT IN ('Cairo', 'Giza');
La declaración devolverá todas las propiedades que no se encuentren ni en las ciudades de El Cairo ni de Guiza.

Propiedades fuera de El Cairo y Giza. Imagen del autor.
Casos de uso WHERE
Sabiendo que WHERE opera con las sentencias SELECT, UPDATE y DELETE, podemos prever que puede utilizarse para tres casos de uso: filtrado a nivel de fila, recuperación de datos y manipulación de datos.
Filtrado por filas
Podemos filtrar las filas de nuestra tabla basándonos en una o varias condiciones. La siguiente consulta filtra las filas para incluir sólo las propiedades de la villa.
SELECT *
FROM rentals
WHERE type = ‘villa’;

Seleccionar propiedades de la villa. Imagen del autor.
Data retrieval
WHERE se puede utilizar para recuperar un punto de datos concreto que estemos buscando. Es similar al filtrado por filas, pero más específico. Suponiendo que necesitemos conocer el ID de la vivienda que estaba disponible el 1 de enero de 2022 en El Cairo, podemos utilizar la siguiente consulta:
SELECT property_id
FROM rentals
WHERE available_date = '2022-01-01'
AND city = 'Cairo';

Recuperar un punto de datos. Imagen del autor.
Manipulación de datos
Por último, WHERE es una gran ayuda para modificar valores y eliminar registros concretos de tu base de datos. Por ejemplo, suponiendo que descubrimos que la propiedad 171 en realidad no admite mascotas, podemos modificar la columna pet_friendly utilizando WHERE en una declaración UPDATE de la siguiente manera:
UPDATE rentals
SET pet_friendly = false
WHERE property_id = 171;
Cómo utilizar la cláusula HAVING en SQL
Ahora, es el momento de pasar a la cláusula HAVING con el mismo nivel de detalle.
Sintaxis y sentencias HAVING
En primer lugar, debemos saber que la cláusula HAVING sólo puede utilizarse en las declaraciones SELECT. Por tanto, la única sintaxis que puede tener es la siguiente:
SELECT grouped_column, aggregate_function(aggregated_column)… etc.
FROM table_name
GROUP BY grouped_column
HAVING condition
Ten en cuenta que puedes añadir más de una columna agrupada y más de una columna agregada. Veremos ejemplos a continuación.
Cómo escribir condiciones HAVING
Al igual que WHERE, las condiciones de HAVING se escriben como expresiones lógicas, pero con un componente adicional, la función de agregación. Así, una condición HAVING consta de 1) función agregada, 2) variable/operando, 3) operador de comparación y 4) valor/resultado.
Funciones agregadas con HAVING
SQL tiene principalmente cinco funciones de agregado, más una sexta que es un caso especial. Estas funciones son:
| Función agregada | Tipo de datos adecuado |
|---|---|
| SUMA() | Numérico |
| AVG() | Numérico |
| MIN() | Numérico, Texto, Fecha/hora |
| MAX() | Numérico, Texto, Fecha/hora |
| CONTAR() | Numérico, Texto, Fecha/hora, Booleano |
Pongamos un ejemplo. Aquí, utilizamos la función COUNT() con GROUP BY para crear una tabla de frecuencias, y utilizamos la condición HAVING como filtro. Concretamente, necesitamos conocer las ciudades que se mencionan 150 veces o menos, lo que en este contexto tendría que ver con el número de inscripciones. Podemos utilizar esta consulta:
SELECT city, COUNT(*) AS properties_count
FROM rentals
GROUP BY city
HAVING COUNT(*) <= 150;

Utilizar COUNT() con HAVING. Imagen del autor.
Comparación y operadores lógicos
HAVING acepta todos los operadores de comparación y lógicos que acepta WHERE. La única diferencia es que el tipo de datos adecuado con HAVING depende sobre todo de la función de agregado, como podemos ver en la tabla anterior.
Casos prácticos HAVING
A diferencia de WHERE, HAVING no se puede utilizar en las declaraciones UPDATE y DELETE; HAVING sólo se utiliza para recuperar datos. A grandes rasgos, esto se traduce en dos escenarios:
Filtrado a nivel de grupo
Este es el uso común y normal de HAVING. Un ejemplo es devolver sólo las ciudades que tienen precios medios de alquiler inferiores a 2.700 $.
SELECT city, AVG(rental_price) AS avg_price
FROM rentals
GROUP BY city
HAVING AVG(rental_price) < 2700;
Filtrado de una fila
Éste es un caso poco común, pero HAVING puede utilizarse para devolver una agregación de una sola fila, como una métrica o un KPI, sólo si cumple una determinada condición. Esto puede conseguirse mediante el uso de HAVING sin GROUP BY. En el ejemplo siguiente, devolvemos el precio medio del alquiler sólo si es inferior a 2.800 $. Si la medida cumple la condición, tendríamos un resultado de una sola fila. Si no, tendríamos una mesa vacía.
SELECT AVG(rental_price) as avg_price
FROM rentals
HAVING AVG(rental_price) > 2800;
Combinar WHERE y HAVING
WHERE y HAVING pueden combinarse para filtrar tablas tanto antes como después de la agregación. En el siguiente ejemplo, devolvemos el recuento de propiedades en cada ciudad, contando sólo las propiedades que admiten mascotas, y filtrando a sólo las ciudades que tienen más de 80 propiedades.
SELECT city, COUNT(*) AS number_properties
FROM rentals
WHERE pet_friendly = true
GROUP BY city
HAVING COUNT(*) > 80;

Combinación básica de WHERE y HAVING. Imagen del autor.
La diferencia entre DÓNDE y TENER en el rendimiento
Sabemos que la cláusula WHERE se aplica antes de la agrupación o agregación. Pero también debemos saber que, por esta razón, porque reduce el número de filas procesadas al principio de la consulta, WHERE es más eficaz para filtrar filas individuales.
Sabemos, por otra parte, que la cláusula HAVING se aplica después de la agregación y filtra el conjunto de resultados basándose en los datos agrupados. Por esta razón, como procesa los datos después de haber agrupado todas las filas, suele ser menos eficaz que WHERE, aunque sigue siendo necesario para las condiciones que implican funciones agregadas.
Veamos esta consulta:
SELECT city, COUNT(*)
FROM rentals
GROUP BY city
HAVING rental_price < 2700;
Esta consulta es ineficaz porque la condición rental_price no depende de ninguna agregación: filtra filas individuales. Esta consulta agrupará primero todos los alquileres por ciudad, los contará y luego filtrará el resultado, lo que es ineficaz porque procesa filas innecesarias. Por esta razón, ésta habría sido una consulta más rápida:
SELECT city, COUNT(*)
FROM rentals
WHERE rental_price < 2700
GROUP BY city;
Consejos de optimización WHERE y HAVING
Basándonos en lo anterior, podemos ver algunas de las buenas prácticas que pueden optimizar nuestro uso de las cláusulas WHERE y HAVING. Esto es importante si tienes grandes conjuntos de datos.
-
Sé muy selectivo: Filtra según los valores a los que necesites filtrar y nada más. Esto ayudará a reducir el número de filas de la vista y, por tanto, mejorará la eficacia de la consulta.
-
Sé sencillo: Elimina las condiciones, agregaciones y elaboraciones de tipo innecesarias. Definitivamente, todos estos extras tienen un precio computacional.
-
Filtra pronto: Si estás haciendo una agregación a nivel de grupo, filtra previamente las filas con
WHEREpara que el proceso de agrupación sea más rápido. Al hacerlo, estarías reduciendo el número de filas que hay que procesar en la agrupación.
Tabla comparativa
Resumamos nuestras ideas en una tabla práctica:
| Comparison | DONDE | TENIENDO |
|---|---|---|
| Objetivo principal | Filtrado por filas | Filtrado a nivel de grupo |
| Sintaxis básica | SELECCIONA columna1, columna2... FROM nombre_tabla WHERE condición; | SELECCIONA columna_agrupada, función_agrupada(columna_agrupada)... FROM nombre_tabla GROUP BY columna_agrupada HAVING condición; |
| Orden de evaluación | Antes de GROUP BY | Después de GROUP BY |
| Declaraciones compatibles | SELECCIONAR, ACTUALIZAR, ELIMINAR | SELECCIONA |
| Condiciones | No se pueden incluir funciones agregadas | Debe incluir funciones agregadas |
| Casos prácticos | Filtrado por filas Recuperación de datos Manipulación de datos | Filtrado a nivel de grupo Filtrado de una fila |
| Subqueries | Puede trabajar con subconsultas | Deben escribirse como CTEs |
Conclusión
A lo largo del artículo, hemos explorado la principal diferencia entre WHERE y HAVING en SQL, que consiste en que la cláusula WHERE filtra las filas antes de la agregación, mientras que la cláusula HAVING filtra los datos agrupados después de la agregación. También exploramos algunas de las diferencias menos conocidas, como el hecho de que WHERE puede funcionar con las declaraciones SELECT, UPDATE y DELETE, pero HAVING sólo funciona con SELECT. También hablamos un poco sobre el rendimiento.
La hoja de trucos de los fundamentos de SQL de DataCamp proporciona un buen resumen de las cláusulas WHERE y HAVING, y algunas orientaciones sobre cómo realizar filtrados en SQL. Además, si te estás iniciando en SQL, te interesará echar un vistazo al itinerario profesional Fundamentos de SQL y al itinerario profesional Analista de Datos Asociado en SQL.

Islam es analista de datos, facilitador en el Instituto KPI y profesor en la Universidad de El Cairo. Con formación periodística, Islam tiene intereses diversos, como la escritura, la filosofía, los medios de comunicación, la tecnología y la cultura.
Preguntas frecuentes
¿Cuál es la diferencia entre DONDE y TENER?
WHERE realiza el filtrado a nivel de fila, mientras que HAVING lo hace a nivel de grupo.
¿Puedo combinar WHERE y HAVING en una consulta?
Sí, y es muy recomendable utilizar WHERE si vas a utilizar HAVING.
¿Puede WHERE funcionar con funciones agregadas como HAVING?
No, sólo HAVING puede trabajar con funciones agregadas.
¿Funcionan WHERE y HAVING con los mismos operadores lógicos y de comparación?
Sí, ambos funcionan con los mismos operadores, ya que las condiciones WHERE y HAVING se escriben como expresiones lógicas.
¿Puedo utilizar HAVING sin GROUP BY?
HAVING se utiliza generalmente después de la agrupación con GROUP BY. La única excepción es el filtrado de vistas de un solo valor (como calcular una métrica).
