Skip to content

Filtros: LIKE, IN, BETWEEN ​

Con = y > puedes filtrar mucho, pero los buscadores reales necesitan más: "productos que contengan libro", "clientes de estas tres ciudades", "pedidos entre dos fechas", "productos sin categoría". En esta lección dominarás LIKE, IN, BETWEEN, IS NULL, la precedencia de AND/OR, la expresión CASE y las funciones de texto y fecha más útiles.

Concepto ​

Piensa en WHERE como el filtro de búsqueda de una tienda en línea: cada casilla que marcas (categoría, rango de precio, texto buscado) es una condición. Estos operadores te dejan expresar esas casillas de forma corta y legible.

LIKE: buscar por patrón ​

LIKE compara textos usando comodines:

ComodínSignificaEjemploCoincide con
%Cero o más caracteres'Libro%'Libro, Libro Aprende SQL
_Exactamente un carácter'_ana'Ana, Lana (si existiera)
sql
-- Productos cuyo nombre empieza con "T"
SELECT nombre FROM productos WHERE nombre LIKE 'T%';
nombre
Teclado mecánico
Taza térmica
sql
-- Productos que contienen "de" en cualquier parte
SELECT nombre FROM productos WHERE nombre LIKE '%de%';
nombre
Libro Aprende SQL
Cien años de soledad
Lámpara de escritorio

¿Por qué salió el libro? Porque "Aprende" contiene "de": LIKE busca caracteres, no palabras completas.

sql
-- Emails que terminan en @correo.com
SELECT email FROM clientes WHERE email LIKE '%@correo.com';

¿Distingue mayúsculas? ​

SGBDLIKEAlternativa
MySQLNo distingue (con collation _ci)—
PostgreSQLSí distingueILIKE no distingue
SQLiteNo distingue para ASCII—

Forma portable de buscar sin importar mayúsculas:

sql
SELECT nombre FROM productos WHERE LOWER(nombre) LIKE '%taza%';

Error común

LIKE '%texto%' (con % al inicio) no puede usar índices normales: en tablas grandes recorre todas las filas. Para buscadores serios usa búsqueda de texto completo (PostgreSQL o FULLTEXT en MySQL).

IN: pertenece a una lista ​

En vez de encadenar muchos OR:

sql
-- Largo
SELECT nombre, ciudad FROM clientes
WHERE ciudad = 'Monterrey' OR ciudad = 'Puebla' OR ciudad = 'Guadalajara';

-- Corto y legible
SELECT nombre, ciudad FROM clientes
WHERE ciudad IN ('Monterrey', 'Puebla', 'Guadalajara');
nombreciudad
Carlos RuizGuadalajara
María PérezMonterrey
Lucía GómezPuebla

NOT IN invierte:

sql
SELECT id, estado FROM pedidos WHERE estado NOT IN ('entregado', 'cancelado');
idestado
3enviado
4pendiente

IN también acepta una subconsulta (lo verás en Subconsultas y CTEs):

sql
-- Clientes que tienen al menos un pedido
SELECT nombre FROM clientes
WHERE id IN (SELECT cliente_id FROM pedidos);

NOT IN con NULL

Si la lista o subconsulta de un NOT IN contiene un NULL, el resultado es vacío. Ejemplo: WHERE id NOT IN (SELECT categoria_id FROM productos) no devuelve nada porque el Cable USB-C tiene categoria_id NULL. Usa NOT EXISTS o filtra los nulos con WHERE categoria_id IS NOT NULL.

BETWEEN: dentro de un rango ​

BETWEEN a AND b incluye ambos extremos:

sql
SELECT nombre, precio FROM productos
WHERE precio BETWEEN 300 AND 1000
ORDER BY precio;
nombreprecio
Libro Aprende SQL349.00
Lámpara de escritorio459.00
Audífonos Bluetooth899.00

Con fechas:

sql
SELECT id, fecha FROM pedidos
WHERE fecha BETWEEN '2024-05-01' AND '2024-05-31';
idfecha
12024-05-02
22024-05-10

BETWEEN con fecha y hora

Si la columna es TIMESTAMP, BETWEEN '2024-05-01' AND '2024-05-31' excluye casi todo el día 31 (lo toma como 31 a las 00:00:00). Para fechas con hora usa un rango semiabierto: WHERE creado_en >= '2024-05-01' AND creado_en < '2024-06-01'

IS NULL e IS NOT NULL ​

sql
-- Productos sin categoría
SELECT nombre FROM productos WHERE categoria_id IS NULL;
nombre
Cable USB-C
sql
-- Productos con categoría
SELECT COUNT(*) FROM productos WHERE categoria_id IS NOT NULL;  -- 7

Precedencia: AND antes que OR ​

AND se evalúa antes que OR, igual que la multiplicación antes que la suma. Mira este error típico:

sql
-- Intención: productos de Libros o Hogar que cuesten menos de 300
SELECT nombre, categoria_id, precio FROM productos
WHERE categoria_id = 2 OR categoria_id = 3 AND precio < 300;
nombrecategoria_idprecio
Libro Aprende SQL2349.00
Cien años de soledad2289.00
Taza térmica3199.00

¡Salió un libro de 349! La BD lo leyó como categoria_id = 2 OR (categoria_id = 3 AND precio < 300). Con paréntesis:

sql
SELECT nombre, categoria_id, precio FROM productos
WHERE (categoria_id = 2 OR categoria_id = 3) AND precio < 300;
-- o mejor: WHERE categoria_id IN (2, 3) AND precio < 300;
nombrecategoria_idprecio
Cien años de soledad2289.00
Taza térmica3199.00

Buena práctica

Siempre que mezcles AND y OR, usa paréntesis aunque no hagan falta. Tu yo del futuro te lo agradecerá.

CASE: condiciones dentro del SELECT ​

CASE es el "if" de SQL. Devuelve un valor según condiciones:

sql
SELECT
  nombre,
  stock,
  CASE
    WHEN stock = 0   THEN 'Agotado'
    WHEN stock <= 10 THEN 'Pocas piezas'
    WHEN stock <= 30 THEN 'Disponible'
    ELSE 'Mucho stock'
  END AS disponibilidad
FROM productos
ORDER BY stock;
nombrestockdisponibilidad
Monitor 24 pulgadas5Pocas piezas
Teclado mecánico10Pocas piezas
Lámpara de escritorio15Disponible
Audífonos Bluetooth25Disponible
Cien años de soledad30Disponible
Libro Aprende SQL40Mucho stock
Taza térmica50Mucho stock
Cable USB-C100Mucho stock

Las condiciones se evalúan en orden y se queda con la primera verdadera. CASE también sirve en ORDER BY para un orden personalizado:

sql
SELECT id, estado FROM pedidos
ORDER BY CASE estado
  WHEN 'pendiente' THEN 1
  WHEN 'enviado'   THEN 2
  WHEN 'entregado' THEN 3
  ELSE 4
END;
idestado
4pendiente
3enviado
1entregado
2entregado
5cancelado

Funciones de texto útiles ​

FunciónEjemploResultado
UPPER(x) / LOWER(x)UPPER('ana')ANA
LENGTH(x)LENGTH('Hola')4 (en MySQL cuenta bytes; usa CHAR_LENGTH)
TRIM(x)TRIM(' hola ')hola
SUBSTRING(x, inicio, n)SUBSTRING('Monterrey', 1, 3)Mon
REPLACE(x, a, b)REPLACE('a-b', '-', '/')a/b
CONCAT(a, b)CONCAT('Hola ', 'Ana')Hola Ana
sql
-- Dominio del correo de cada cliente
SELECT email, SUBSTRING(email, POSITION('@' IN email) + 1) AS dominio
FROM clientes;

Funciones de fecha útiles ​

Aquí los motores difieren bastante:

NecesidadMySQLPostgreSQLSQLite
HoyCURDATE()CURRENT_DATEDATE('now')
Año de una fechaYEAR(fecha)EXTRACT(YEAR FROM fecha)strftime('%Y', fecha)
MesMONTH(fecha)EXTRACT(MONTH FROM fecha)strftime('%m', fecha)
Sumar 7 díasfecha + INTERVAL 7 DAYfecha + INTERVAL '7 days'DATE(fecha, '+7 days')
Días entre fechasDATEDIFF(f2, f1)f2 - f1julianday(f2) - julianday(f1)

EXTRACT(YEAR FROM fecha) funciona en MySQL y PostgreSQL:

sql
-- Pedidos de junio (cualquier año)
SELECT id, fecha FROM pedidos WHERE EXTRACT(MONTH FROM fecha) = 6;
idfecha
32024-06-01
42024-06-15
52024-06-20

Rendimiento

Aplicar una función a la columna (EXTRACT(MONTH FROM fecha) = 6) impide usar un índice sobre fecha. Si buscas un mes concreto, prefiere el rango: fecha >= '2024-06-01' AND fecha < '2024-07-01'.

Caso real: el buscador de la tienda ​

El usuario escribe "a", elige las categorías Electrónica y Hogar y un precio entre 100 y 1,000:

sql
SELECT id, nombre, precio
FROM productos
WHERE LOWER(nombre) LIKE '%a%'
  AND categoria_id IN (1, 3)
  AND precio BETWEEN 100 AND 1000
  AND stock > 0
ORDER BY precio;
idnombreprecio
7Taza térmica199.00
6Lámpara de escritorio459.00
1Audífonos Bluetooth899.00

Ejercicios ​

  1. Muestra los clientes cuyo nombre contiene "ar" (sin importar mayúsculas).
  2. Muestra los productos cuyo id sea 2, 4 o 6.
  3. Muestra los clientes registrados en febrero de 2024 usando BETWEEN.
  4. Lista los productos con una columna rango que diga 'Económico' si cuesta menos de 300, 'Medio' si cuesta hasta 1000 y 'Premium' si cuesta más.
  5. ¿Qué devuelve esta consulta y por qué? SELECT nombre FROM productos WHERE categoria_id <> 1;
Ver solución
sql
-- 1
SELECT nombre FROM clientes WHERE LOWER(nombre) LIKE '%ar%';
nombre
Carlos Ruiz
María Pérez
sql
-- 2
SELECT id, nombre FROM productos WHERE id IN (2, 4, 6);

-- 3
SELECT nombre, fecha_registro FROM clientes
WHERE fecha_registro BETWEEN '2024-02-01' AND '2024-02-29';
nombrefecha_registro
Carlos Ruiz2024-02-03
María Pérez2024-02-20
sql
-- 4
SELECT nombre, precio,
  CASE
    WHEN precio < 300   THEN 'Económico'
    WHEN precio <= 1000 THEN 'Medio'
    ELSE 'Premium'
  END AS rango
FROM productos;
nombrepreciorango
Audífonos Bluetooth899.00Medio
Teclado mecánico1250.00Premium
Monitor 24 pulgadas3499.00Premium
Libro Aprende SQL349.00Medio
Cien años de soledad289.00Económico
Lámpara de escritorio459.00Medio
Taza térmica199.00Económico
Cable USB-C99.00Económico
  1. Devuelve los productos de Libros y Hogar (4 filas), pero no el Cable USB-C: su categoria_id es NULL y NULL <> 1 no es verdadero sino desconocido. Para incluirlo: WHERE categoria_id <> 1 OR categoria_id IS NULL.

Resumen ​

  • LIKE busca patrones con % (cualquier cosa) y _ (un carácter). En PostgreSQL existe ILIKE.
  • IN (...) reemplaza cadenas de OR; cuidado con NOT IN y los NULL.
  • BETWEEN a AND b incluye los extremos; con fechas y horas usa rangos semiabiertos.
  • IS NULL / IS NOT NULL para valores vacíos.
  • AND va antes que OR: usa paréntesis.
  • CASE WHEN ... THEN ... END crea columnas condicionales y órdenes personalizados.

Academia Web — aprende, copia y construye.