WHERE es un filtro de filas. Sin él, tu consulta devuelve todas las filas de la tabla. Con él, solo las filas que realmente quieres.
Piensa en una tabla como en un armario lleno de ropa. SELECT * FROM clothes significa «dame todo lo que hay ahí». SELECT * FROM clothes WHERE color = 'red' significa «dame solo las prendas rojas». WHERE es ese filtro.
Por qué importa WHERE
Las tablas del mundo real contienen decenas de miles —a veces millones— de filas. Devolverlas todas es:
- Lento: la base de datos hace más trabajo y la red transporta más datos.
- Inútil: normalmente quieres usuarios, pedidos o productos concretos, no la tabla entera.
WHERE recorta el ruido del lado de la base de datos antes de que los datos lleguen a ti. Es una de las primeras herramientas que aprende todo desarrollador y analista de SQL — sin él no llegarás lejos.
Cómo funciona por dentro
Cuando escribes SELECT ... FROM users WHERE age > 18, la base de datos hace algo sencillo:
- Lee cada fila de
users una a una.
- Inserta el valor
age de la fila en la condición age > 18.
- Si la condición es
TRUE, la fila pasa al resultado. Si es FALSE, se descarta.
WHERE no es más que una prueba de sí/no aplicada a cada fila.
Sintaxis básica
SELECT name, age
FROM users
WHERE age > 18;
Línea por línea:
SELECT name, age — qué columnas quieres de vuelta.
FROM users — de qué tabla.
WHERE age > 18 — qué filas conservar (solo personas mayores de 18).
El resultado es una lista de usuarios adultos, solo con su nombre y su edad (sin correo, teléfono ni nada más que no hayamos pedido).
Qué puedes poner después de WHERE
1. Comparaciones
= — igual
<> o != — distinto
>, <, >=, <= — mayor que, menor que, etc.
SELECT * FROM products WHERE price > 1000;
SELECT * FROM users WHERE country = 'Russia';
SELECT * FROM orders WHERE status <> 'cancelled';
Ejemplo resuelto. Dada la tabla products:
| id | name | price |
|---|
| 1 | Mug | 350 |
| 2 | Kettle | 1200 |
| 3 | Microwave | 5000 |
| 4 | Spoon | 80 |
Consulta:
SELECT name, price FROM products WHERE price > 1000;
Resultado:
| name | price |
|---|
| Kettle | 1200 |
| Microwave | 5000 |
Mug y Spoon quedaron fuera — su precio está por debajo de 1000.
2. Operadores lógicos AND, OR, NOT
AND — ambas condiciones deben ser verdaderas
OR — al menos una debe ser verdadera
NOT — niega una condición
SELECT * FROM users
WHERE country = 'Russia' AND age >= 21;
SELECT * FROM orders
WHERE status = 'paid' OR status = 'shipped';
SELECT * FROM products
WHERE NOT in_stock;
AND frente a OR, en la práctica. Tabla users:
| id | name | country | age |
|---|
| 1 | Anna | Russia | 25 |
| 2 | Bob | USA | 30 |
| 3 | Vera | Russia | 17 |
| 4 | Grisha | Russia | 40 |
Consulta con AND (ambas condiciones):
SELECT name FROM users WHERE country = 'Russia' AND age >= 21;
Resultado:
Vera quedó fuera (17, por debajo de 21). Bob quedó fuera (no es Russia). Solo Anna y Grisha cumplen ambas condiciones a la vez.
La misma consulta con OR (al menos una):
SELECT name FROM users WHERE country = 'Russia' OR age >= 21;
Resultado:
Ahora coinciden las cuatro. Anna, Vera, Grisha — Russia. Bob — 30 (≥ 21). Cada fila tiene al menos una condición verdadera. Una diferencia aleccionadora entre AND y OR.
3. Un conjunto de valores: IN
Cuando quieres comprobar si un valor es una de varias opciones:
SELECT * FROM users
WHERE country IN ('Russia', 'Belarus', 'Kazakhstan');
Es la forma abreviada de:
WHERE country = 'Russia' OR country = 'Belarus' OR country = 'Kazakhstan'
IN se lee más limpio, sobre todo cuando la lista crece.
También existe NOT IN:
SELECT * FROM users WHERE country NOT IN ('USA', 'Canada');
4. Un rango: BETWEEN
Estupendo para fechas, números — cualquier cosa ordenable.
SELECT * FROM orders
WHERE created_at BETWEEN '2024-01-01' AND '2024-12-31';
SELECT * FROM products
WHERE price BETWEEN 100 AND 500;
Importante: BETWEEN incluye ambos extremos. BETWEEN 100 AND 500 es lo mismo que >= 100 AND <= 500. El 100 exacto y el 500 exacto también entran.
5. Búsqueda de texto: LIKE
Para coincidencias parciales de cadenas:
SELECT * FROM users WHERE email LIKE '%@gmail.com';
SELECT * FROM users WHERE name LIKE 'A%';
SELECT * FROM users WHERE name LIKE '%nn%';
Dos comodines en LIKE:
% — cualquier número de caracteres (incluido cero)
_ — exactamente un carácter
Ejemplo con _: WHERE phone LIKE '+1 555___' — teléfonos que empiezan por +1 555 seguido de tres caracteres cualesquiera.
6. NULL es algo aparte
Esta es la trampa más común para principiantes. NULL en SQL no es un valor — es la ausencia de uno. «Desconocido». «Sin rellenar».
Y no lo puedes comparar con =. En ningún sitio. Incluso NULL = NULL no devuelve TRUE, sino NULL otra vez («lo desconocido igual a lo desconocido — quién sabe»).
SELECT * FROM users WHERE deleted_at = NULL;
SELECT * FROM users WHERE deleted_at IS NULL;
SELECT * FROM users WHERE deleted_at IS NOT NULL;
Recuerda: para NULL — solo IS NULL e IS NOT NULL, nunca = ni <>.
Ejemplo más grande: antes y después
Dada la tabla orders:
| id | user_id | amount | status | country |
|---|
| 1 | 10 | 500 | paid | Russia |
| 2 | 11 | 1500 | paid | USA |
| 3 | 12 | 200 | cancelled | Russia |
| 4 | 13 | 3000 | paid | Russia |
| 5 | 14 | 800 | pending | Russia |
| 6 | 15 | 4500 | paid | Belarus |
Objetivo: «pedidos pagados de Russia, con importe superior a 1000».
Consulta:
SELECT id, amount
FROM orders
WHERE status = 'paid'
AND country = 'Russia'
AND amount > 1000;
Resultado:
Quién quedó fuera y por qué:
- #1: pagado y de Russia, pero importe 500 — no cumple
amount > 1000.
- #2: pagado y suficientemente grande, pero USA — no es Russia.
- #3: cancelado — no está pagado.
- #5: pendiente — no está pagado.
- #6: pagado y suficientemente grande, pero Belarus — no es Russia.
Solo el #4 cumple las tres condiciones a la vez (AND).
Ahora cambia AND por OR con los mismos datos:
SELECT id, amount, country, status
FROM orders
WHERE status = 'paid'
OR country = 'Russia'
OR amount > 1000;
Resultado:
| id | amount | country | status |
|---|
| 1 | 500 | Russia | paid |
| 2 | 1500 | USA | paid |
| 3 | 200 | Russia | cancelled |
| 4 | 3000 | Russia | paid |
| 5 | 800 | Russia | pending |
| 6 | 4500 | Belarus | paid |
Pasan las seis filas. Cada fila cumple al menos una de las tres condiciones. Un sólido recordatorio de lo diferentes que son AND y OR.
Una más: fechas y texto
La misma tabla orders, con fechas y correo:
Objetivo: «pedidos de 2024, solo de usuarios de gmail».
SELECT id, email, amount
FROM orders
WHERE created_at BETWEEN '2024-01-01' AND '2024-12-31'
AND email LIKE '%@gmail.com';
Resultado:
El pedido #2 queda fuera (yandex.ru, no gmail). El #4 queda fuera (2025, no 2024).
Errores habituales de principiante
1. Comparar NULL con =. Nunca funciona. Usa IS NULL / IS NOT NULL.
2. Las comillas. Las cadenas y las fechas van entre comillas simples '...'. Los números no necesitan comillas. Las comillas dobles "..." en PostgreSQL son para identificadores (nombres de columna), no para cadenas.
WHERE name = 'Alice' AND age = 30
WHERE name = "Alice"
3. Confundir AND y OR. Usa siempre paréntesis en las condiciones compuestas para hacer explícita la precedencia:
WHERE country = 'Russia'
AND ((sex = 'M' AND age > 21) OR (sex = 'F' AND age > 18));
Sin paréntesis, la lógica puede acabar en un sitio completamente distinto del que pretendías.
4. Filtrar agregaciones con WHERE. No funciona. WHERE se ejecuta antes de la agrupación y no sabe nada de COUNT, SUM, etc. Para condiciones sobre agregaciones existe HAVING.
SELECT country, COUNT(*) FROM users
GROUP BY country
WHERE COUNT(*) > 100;
SELECT country, COUNT(*) FROM users
GROUP BY country
HAVING COUNT(*) > 100;
5. Sensibilidad a mayúsculas y minúsculas. WHERE name = 'Alice' y WHERE name = 'alice' son condiciones distintas en la mayoría de las bases de datos. Si las mayúsculas no deben importar, normaliza ambos lados:
WHERE LOWER(name) = 'alice'
6. Olvidar el AND entre condiciones. Varias condiciones necesitan un AND u OR explícito — aquí no hay una coma implícita.
WHERE country = 'Russia' age > 21
WHERE country = 'Russia' AND age > 21
Resumen rápido
WHERE filtra filas en SELECT, UPDATE y DELETE.
- Las condiciones usan comparaciones,
AND/OR/NOT, IN, BETWEEN, LIKE.
- Para
NULL, usa IS NULL / IS NOT NULL — las comparaciones normales fallan en silencio.
- Cuanto más ajustado sea tu
WHERE, menos datos devuelve la base de datos — y más rápido va todo.
- Usa siempre paréntesis en las condiciones compuestas
AND/OR. No adivines la precedencia, escríbela.
Pruébalo tú
Tres ejercicios de dificultad creciente sobre la misma tabla orders:
- Encuentra todos los pedidos pagados por encima de 500.
- Encuentra los pedidos de junio de 2024 de usuarios fuera de Russia.
- Encuentra los pedidos donde
delivered_at aún no está establecido (es decir, NULL).
Escribe primero las consultas por tu cuenta y luego compruébate. Si no encajan de inmediato — es totalmente normal. SQL se lee de izquierda a derecha como el inglés, y se vuelve automático con la repetición.
WHEREes un filtro de filas. Sin él, tu consulta devuelve todas las filas de la tabla. Con él, solo las filas que realmente quieres.Piensa en una tabla como en un armario lleno de ropa.
SELECT * FROM clothessignifica «dame todo lo que hay ahí».SELECT * FROM clothes WHERE color = 'red'significa «dame solo las prendas rojas».WHEREes ese filtro.Por qué importa WHERE
Las tablas del mundo real contienen decenas de miles —a veces millones— de filas. Devolverlas todas es:
WHERErecorta el ruido del lado de la base de datos antes de que los datos lleguen a ti. Es una de las primeras herramientas que aprende todo desarrollador y analista de SQL — sin él no llegarás lejos.Cómo funciona por dentro
Cuando escribes
SELECT ... FROM users WHERE age > 18, la base de datos hace algo sencillo:usersuna a una.agede la fila en la condiciónage > 18.TRUE, la fila pasa al resultado. Si esFALSE, se descarta.WHEREno es más que una prueba de sí/no aplicada a cada fila.Sintaxis básica
SELECT name, age FROM users WHERE age > 18;Línea por línea:
SELECT name, age— qué columnas quieres de vuelta.FROM users— de qué tabla.WHERE age > 18— qué filas conservar (solo personas mayores de 18).El resultado es una lista de usuarios adultos, solo con su nombre y su edad (sin correo, teléfono ni nada más que no hayamos pedido).
Qué puedes poner después de WHERE
1. Comparaciones
=— igual<>o!=— distinto>,<,>=,<=— mayor que, menor que, etc.SELECT * FROM products WHERE price > 1000; SELECT * FROM users WHERE country = 'Russia'; SELECT * FROM orders WHERE status <> 'cancelled';Ejemplo resuelto. Dada la tabla
products:Consulta:
SELECT name, price FROM products WHERE price > 1000;Resultado:
Mug y Spoon quedaron fuera — su precio está por debajo de 1000.
2. Operadores lógicos AND, OR, NOT
AND— ambas condiciones deben ser verdaderasOR— al menos una debe ser verdaderaNOT— niega una condiciónSELECT * FROM users WHERE country = 'Russia' AND age >= 21; SELECT * FROM orders WHERE status = 'paid' OR status = 'shipped'; SELECT * FROM products WHERE NOT in_stock;AND frente a OR, en la práctica. Tabla
users:Consulta con
AND(ambas condiciones):SELECT name FROM users WHERE country = 'Russia' AND age >= 21;Resultado:
Vera quedó fuera (17, por debajo de 21). Bob quedó fuera (no es Russia). Solo Anna y Grisha cumplen ambas condiciones a la vez.
La misma consulta con
OR(al menos una):SELECT name FROM users WHERE country = 'Russia' OR age >= 21;Resultado:
Ahora coinciden las cuatro. Anna, Vera, Grisha — Russia. Bob — 30 (≥ 21). Cada fila tiene al menos una condición verdadera. Una diferencia aleccionadora entre
ANDyOR.3. Un conjunto de valores: IN
Cuando quieres comprobar si un valor es una de varias opciones:
SELECT * FROM users WHERE country IN ('Russia', 'Belarus', 'Kazakhstan');Es la forma abreviada de:
WHERE country = 'Russia' OR country = 'Belarus' OR country = 'Kazakhstan'INse lee más limpio, sobre todo cuando la lista crece.También existe
NOT IN:SELECT * FROM users WHERE country NOT IN ('USA', 'Canada');4. Un rango: BETWEEN
Estupendo para fechas, números — cualquier cosa ordenable.
SELECT * FROM orders WHERE created_at BETWEEN '2024-01-01' AND '2024-12-31'; SELECT * FROM products WHERE price BETWEEN 100 AND 500;Importante:
BETWEENincluye ambos extremos.BETWEEN 100 AND 500es lo mismo que>= 100 AND <= 500. El 100 exacto y el 500 exacto también entran.5. Búsqueda de texto: LIKE
Para coincidencias parciales de cadenas:
-- Todos los que tienen una dirección de gmail SELECT * FROM users WHERE email LIKE '%@gmail.com'; -- Nombres que empiezan por 'A' SELECT * FROM users WHERE name LIKE 'A%'; -- Nombres que contienen 'nn' en cualquier lugar SELECT * FROM users WHERE name LIKE '%nn%';Dos comodines en
LIKE:%— cualquier número de caracteres (incluido cero)_— exactamente un carácterEjemplo con
_:WHERE phone LIKE '+1 555___'— teléfonos que empiezan por +1 555 seguido de tres caracteres cualesquiera.6. NULL es algo aparte
Esta es la trampa más común para principiantes.
NULLen SQL no es un valor — es la ausencia de uno. «Desconocido». «Sin rellenar».Y no lo puedes comparar con
=. En ningún sitio. InclusoNULL = NULLno devuelveTRUE, sinoNULLotra vez («lo desconocido igual a lo desconocido — quién sabe»).-- MAL: no devuelve nada, aunque existan NULL SELECT * FROM users WHERE deleted_at = NULL; -- BIEN SELECT * FROM users WHERE deleted_at IS NULL; SELECT * FROM users WHERE deleted_at IS NOT NULL;Recuerda: para
NULL— soloIS NULLeIS NOT NULL, nunca=ni<>.Ejemplo más grande: antes y después
Dada la tabla
orders:Objetivo: «pedidos pagados de Russia, con importe superior a 1000».
Consulta:
SELECT id, amount FROM orders WHERE status = 'paid' AND country = 'Russia' AND amount > 1000;Resultado:
Quién quedó fuera y por qué:
amount > 1000.Solo el #4 cumple las tres condiciones a la vez (
AND).Ahora cambia
ANDporORcon los mismos datos:SELECT id, amount, country, status FROM orders WHERE status = 'paid' OR country = 'Russia' OR amount > 1000;Resultado:
Pasan las seis filas. Cada fila cumple al menos una de las tres condiciones. Un sólido recordatorio de lo diferentes que son
ANDyOR.Una más: fechas y texto
La misma tabla
orders, con fechas y correo:Objetivo: «pedidos de 2024, solo de usuarios de gmail».
SELECT id, email, amount FROM orders WHERE created_at BETWEEN '2024-01-01' AND '2024-12-31' AND email LIKE '%@gmail.com';Resultado:
El pedido #2 queda fuera (yandex.ru, no gmail). El #4 queda fuera (2025, no 2024).
Errores habituales de principiante
1. Comparar NULL con
=. Nunca funciona. UsaIS NULL/IS NOT NULL.2. Las comillas. Las cadenas y las fechas van entre comillas simples
'...'. Los números no necesitan comillas. Las comillas dobles"..."en PostgreSQL son para identificadores (nombres de columna), no para cadenas.-- Bien WHERE name = 'Alice' AND age = 30 -- Mal: esto busca una columna llamada Alice — error WHERE name = "Alice"3. Confundir AND y OR. Usa siempre paréntesis en las condiciones compuestas para hacer explícita la precedencia:
-- Quieres: país Russia AND (hombres mayores de 21 OR mujeres mayores de 18) WHERE country = 'Russia' AND ((sex = 'M' AND age > 21) OR (sex = 'F' AND age > 18));Sin paréntesis, la lógica puede acabar en un sitio completamente distinto del que pretendías.
4. Filtrar agregaciones con WHERE. No funciona.
WHEREse ejecuta antes de la agrupación y no sabe nada deCOUNT,SUM, etc. Para condiciones sobre agregaciones existeHAVING.-- Mal SELECT country, COUNT(*) FROM users GROUP BY country WHERE COUNT(*) > 100; -- Bien SELECT country, COUNT(*) FROM users GROUP BY country HAVING COUNT(*) > 100;5. Sensibilidad a mayúsculas y minúsculas.
WHERE name = 'Alice'yWHERE name = 'alice'son condiciones distintas en la mayoría de las bases de datos. Si las mayúsculas no deben importar, normaliza ambos lados:WHERE LOWER(name) = 'alice'6. Olvidar el AND entre condiciones. Varias condiciones necesitan un
ANDuORexplícito — aquí no hay una coma implícita.-- Mal (sin AND) WHERE country = 'Russia' age > 21 -- Bien WHERE country = 'Russia' AND age > 21Resumen rápido
WHEREfiltra filas enSELECT,UPDATEyDELETE.AND/OR/NOT,IN,BETWEEN,LIKE.NULL, usaIS NULL/IS NOT NULL— las comparaciones normales fallan en silencio.WHERE, menos datos devuelve la base de datos — y más rápido va todo.AND/OR. No adivines la precedencia, escríbela.Pruébalo tú
Tres ejercicios de dificultad creciente sobre la misma tabla
orders:delivered_ataún no está establecido (es decir,NULL).Escribe primero las consultas por tu cuenta y luego compruébate. Si no encajan de inmediato — es totalmente normal. SQL se lee de izquierda a derecha como el inglés, y se vuelve automático con la repetición.