SQLWHEREtutorialbeginner

¿Qué es WHERE en SQL? Filtrado de filas para principiantes

WHERE es el filtro de filas en SQL. En lenguaje llano y con muchos ejemplos: =, IN, BETWEEN, LIKE, IS NULL y AND/OR. Tablas antes y después, trampas para principiantes y una práctica rápida al final.

7 min de lecturaSQL · WHERE · tutorial · beginner

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:

  1. Lee cada fila de users una a una.
  2. Inserta el valor age de la fila en la condición age > 18.
  3. 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:

idnameprice
1Mug350
2Kettle1200
3Microwave5000
4Spoon80

Consulta:

SELECT name, price FROM products WHERE price > 1000;

Resultado:

nameprice
Kettle1200
Microwave5000

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:

idnamecountryage
1AnnaRussia25
2BobUSA30
3VeraRussia17
4GrishaRussia40

Consulta con AND (ambas condiciones):

SELECT name FROM users WHERE country = 'Russia' AND age >= 21;

Resultado:

name
Anna
Grisha

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:

name
Anna
Bob
Vera
Grisha

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:

-- 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á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»).

-- 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 — solo IS NULL e IS NOT NULL, nunca = ni <>.

Ejemplo más grande: antes y después

Dada la tabla orders:

iduser_idamountstatuscountry
110500paidRussia
2111500paidUSA
312200cancelledRussia
4133000paidRussia
514800pendingRussia
6154500paidBelarus

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:

idamount
43000

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:

idamountcountrystatus
1500Russiapaid
21500USApaid
3200Russiacancelled
43000Russiapaid
5800Russiapending
64500Belaruspaid

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:

idcreated_atemailamount
12024-03-10anna@gmail.com500
22024-06-22bob@yandex.ru1500
32024-11-05vera@gmail.com200
42025-01-15grisha@mail.ru3000

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:

idemailamount
1anna@gmail.com500
3vera@gmail.com200

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.

-- 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. WHERE se ejecuta antes de la agrupación y no sabe nada de COUNT, SUM, etc. Para condiciones sobre agregaciones existe HAVING.

-- 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' 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.

-- Mal (sin AND)
WHERE country = 'Russia' age > 21

-- Bien
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:

  1. Encuentra todos los pedidos pagados por encima de 500.
  2. Encuentra los pedidos de junio de 2024 de usuarios fuera de Russia.
  3. 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.

Practica con ejercicios reales

Resuelve ejercicios en el entrenador de SQL con corrección instantánea y pistas.

Abrir el entrenador