SQL: Filtrado de Datos con la Cláusula WHERE

SQL: Filtrado de Datos con la Cláusula WHERE

Tabla de Contenido

El filtrado de datos en SQL es una operación diaria cuando trabajas con bases relacionales: rara vez necesitas todas las filas de una tabla. La cláusula WHERE expresa condiciones precisas para reducir resultados, evitar lecturas innecesarias y alinear la consulta con la lógica de negocio. Este es el artículo #2 de la serie SQL; si necesitas repasar SELECT, FROM y el modelo general de consulta, revisa Fundamentos de SQL.

Note

Aprenderás a usar WHERE con igualdad, desigualdad, rangos, BETWEEN, IN, subconsultas, LIKE, expresiones regulares y NULL, tanto en lectura como en modificación.

La cláusula WHERE y las condiciones booleanas

La cláusula WHERE filtra filas evaluando una o más condiciones. Cada condición produce un resultado lógico que el motor de base de datos usa para decidir si una fila entra o no en el resultado final.

En la práctica, esas condiciones suelen combinar varios tipos de operadores:

  • Operadores de comparación: =, !=, <, >, <>, LIKE, IN, BETWEEN.
  • Operadores aritméticos: +, -, *, /, cuando necesitas comparar expresiones calculadas.
  • Operadores lógicos: AND, OR, NOT, para componer filtros más específicos.

Aunque WHERE es el punto central para filtrar filas, también existe HAVING, que se utiliza después de agrupar datos con GROUP BY. La diferencia es importante: WHERE filtra filas antes de la agregación; HAVING filtra grupos después de calcular agregados.

Condiciones de igualdad

La condición de igualdad compara una columna contra una expresión. Esa expresión puede ser un literal, un número, una fecha o incluso el resultado de una subconsulta.

title = 'RIVER OUTLAW'
fed_id = '111-11-1111'
amount = 375.25
film_id = (SELECT film_id FROM film WHERE title = 'RIVER OUTLAW')

Observemos un caso concreto usando la base de datos de ejemplo Sakila. La consulta obtiene los correos de clientes que rentaron películas el 2005-06-14:

mysql> SELECT c.email
    -> FROM customer c
    ->   INNER JOIN rental r
    ->   ON c.customer_id = r.customer_id
    -> WHERE date(r.rental_date) = '2005-06-14';
+---------------------------------------+
| email                                 |
+---------------------------------------+
| CATHERINE.CAMPBELL@sakilacustomer.org |
| JOYCE.EDWARDS@sakilacustomer.org      |
...
| TERRENCE.GUNDERSON@sakilacustomer.org |
+---------------------------------------+
16 rows in set (0.03 sec)

Aquí date(r.rental_date) transforma el DATETIME a fecha antes de comparar. En producción, aplicar funciones sobre columnas puede limitar el uso eficiente de índices.

Condiciones de desigualdad

La desigualdad expresa el caso contrario: queremos excluir filas que coinciden con un valor. En SQL puedes escribirla con <>, != o usando NOT según el motor y el estilo del equipo.

mysql> SELECT c.email
    -> FROM customer c
    ->   INNER JOIN rental r
    ->   ON c.customer_id = r.customer_id
    -> WHERE date(r.rental_date) <> '2005-06-14';

+-----------------------------------+
| email                             |
+-----------------------------------+
...
| AUSTIN.CINTRON@sakilacustomer.org |
| AUSTIN.CINTRON@sakilacustomer.org |
| AUSTIN.CINTRON@sakilacustomer.org |
| AUSTIN.CINTRON@sakilacustomer.org |
+-----------------------------------+
16028 rows in set (0.03 sec)

La diferencia semántica es directa: en lugar de seleccionar rentas del día indicado, excluimos ese día.

Modificación de datos con condiciones de igualdad

WHERE no solo aparece en SELECT. También es crítico en UPDATE y DELETE, donde define exactamente qué filas serán modificadas o eliminadas.

DELETE FROM rental
WHERE year(rental_date) = 2004;

DELETE FROM rental
WHERE year(rental_date) <> 2005 AND year(rental_date) <> 2006;

El primer caso elimina rentas del año 2004; el segundo elimina rentas que no pertenecen ni a 2005 ni a 2006.

Warning

Antes de ejecutar un DELETE o UPDATE con WHERE, valida la condición con un SELECT equivalente. Un filtro demasiado amplio puede modificar más filas de las esperadas.

Condiciones de rango

Para filtrar rangos puedes combinar operadores como <, <=, > y >= con AND u OR. Esto funciona con fechas, números y otros tipos comparables.

mysql> SELECT customer_id, rental_date
    -> FROM rental
    -> WHERE rental_date < '2005-05-25';
+-------------+---------------------+
| customer_id | rental_date         |
+-------------+---------------------+
|         130 | 2005-05-24 22:53:30 |
|         459 | 2005-05-24 22:54:33 |
...
|         239 | 2005-05-24 23:31:46 |
+-------------+---------------------+
8 rows in set (0.00 sec)

mysql> SELECT customer_id, rental_date
    -> FROM rental
    -> WHERE rental_date <= '2005-06-16'
    ->   AND rental_date >= '2005-06-14';
+-------------+---------------------+
| customer_id | rental_date         |
+-------------+---------------------+
|         416 | 2005-06-14 22:53:33 |
|         516 | 2005-06-14 22:55:13 |
...
|         148 | 2005-06-15 23:20:26 |
|         237 | 2005-06-15 23:36:37 |
|         155 | 2005-06-15 23:55:27 |
|         341 | 2005-06-15 23:57:20 |
|         149 | 2005-06-15 23:58:53 |
+-------------+---------------------+
364 rows in set (0.00 sec)

Usando BETWEEN

BETWEEN permite expresar un rango con una sintaxis más compacta. El valor menor va a la izquierda, el mayor a la derecha, y ambos límites son inclusivos.

mysql> SELECT customer_id, rental_date
    -> FROM rental
    -> WHERE rental_date BETWEEN '2005-06-14' AND '2005-06-16';
+-------------+---------------------+
| customer_id | rental_date         |
+-------------+---------------------+
|         416 | 2005-06-14 22:53:33 |
|         516 | 2005-06-14 22:55:13 |
...
|         148 | 2005-06-15 23:20:26 |
|         237 | 2005-06-15 23:36:37 |
|         155 | 2005-06-15 23:55:27 |
|         341 | 2005-06-15 23:57:20 |
|         149 | 2005-06-15 23:58:53 |
+-------------+---------------------+
364 rows in set (0.00 sec)

Tip

BETWEEN puede usarse con fechas, horas, números y strings. Recuerda que los límites son inclusivos, así que valida cuidadosamente rangos de tiempo cuando trabajes con columnas DATETIME.

Condiciones de pertenencia con IN

Las condiciones de pertenencia permiten verificar si un valor existe dentro de una lista. Primero, analicemos la versión con OR:

mysql> SELECT title, rating
    -> FROM film
    -> WHERE rating = 'G' OR rating = 'PG';
+---------------------------+--------+
| title                     | rating |
+---------------------------+--------+
| ACADEMY DINOSAUR          | PG     |
| ACE GOLDFINGER            | G      |
...
| WEDDING APOLLO            | PG     |
| WEREWOLF LOLA             | G      |
| WEST LION                 | G      |
...
| YOUNG LANGUAGE            | G      |
+---------------------------+--------+
372 rows in set (0.00 sec)

La misma condición puede escribirse de forma más clara con IN:

SELECT title, rating
FROM film
WHERE rating IN ('G','PG');

También puedes combinar pertenencia y negación usando NOT IN:

SELECT title, rating
FROM film
WHERE rating NOT IN ('PG-13','R', 'NC-17');

IN mejora la legibilidad cuando comparas una columna contra múltiples valores discretos y evita repetir la misma columna.

Subconsultas dentro de IN

IN no está limitado a listas escritas manualmente. También puedes usar una subconsulta para calcular dinámicamente los valores válidos de comparación.

mysql> SELECT title, rating
    -> FROM film
    -> WHERE rating IN (SELECT rating FROM film WHERE title LIKE '%PET%');
+---------------------------+--------+
| title                     | rating |
+---------------------------+--------+
| ACADEMY DINOSAUR          | PG     |
| ACE GOLDFINGER            | G      |
...
| WEDDING APOLLO            | PG     |
| WEREWOLF LOLA             | G      |
| WEST LION                 | G      |
...
| YOUNG LANGUAGE            | G      |
+---------------------------+--------+
372 rows in set (0.00 sec)

La subconsulta obtiene los rating de películas cuyo título contiene PET; la consulta externa recupera las películas con esos ratings.

Condiciones de coincidencia con LIKE

Las condiciones de coincidencia permiten buscar patrones de texto en lugar de valores exactos. Con LIKE, SQL ofrece dos comodines principales:

ComodínSignificado
_Exactamente un carácter
%Cualquier cantidad de caracteres, incluyendo cero

Consideremos este patrón: _A_T%S. Significa: un carácter cualquiera, luego A, luego un carácter cualquiera, luego T, luego cualquier secuencia, y finalmente S.

mysql> SELECT last_name, first_name
    -> FROM customer
    -> WHERE last_name LIKE '_A_T%S';
+-----------+------------+
| last_name | first_name |
+-----------+------------+
| MATTHEWS  | ERICA      |
| WALTERS   | CASSANDRA  |
| WATTS     | SHELLY     |
+-----------+------------+
3 rows in set (0.00 sec)

LIKE es útil para búsquedas simples. Un patrón que inicia con %, como '%PET%', suele ser más costoso porque limita el uso de índices tradicionales.

Expresiones regulares

Algunos motores permiten filtrar texto con expresiones regulares. En MySQL, por ejemplo, se usa REGEXP. Otros motores tienen variantes propias, así que siempre valida la sintaxis de tu base de datos.

mysql> SELECT last_name, first_name
    -> FROM customer
    -> WHERE last_name REGEXP '^[QY]';
+-------------+------------+
| last_name   | first_name |
+-------------+------------+
| YOUNG       | CYNTHIA    |
| QUALLS      | STEPHEN    |
| QUINTANILLA | ROGER      |
| YANEZ       | LUIS       |
| YEE         | MARVIN     |
| QUIGLEY     | TROY       |
+-------------+------------+
6 rows in set (0.16 sec)

El patrón ^[QY] indica que el apellido debe iniciar con Q o Y. Las expresiones regulares son más expresivas que LIKE, pero menos portables entre motores.

Filtrado de valores NULL

NULL es un caso especial en SQL. No representa false, cero ni una cadena vacía; representa ausencia de valor o valor desconocido. Por esa razón, no debes comparar NULL con =.

Para consultar valores nulos se usa IS NULL, y para excluirlos se usa IS NOT NULL.

mysql> SELECT rental_id, customer_id
    -> FROM rental
    -> WHERE return_date IS NULL;
+-----------+-------------+
| rental_id | customer_id |
+-----------+-------------+
|     11496 |         155 |
|     11541 |         335 |
...
|     15867 |         505 |
|     15875 |          41 |
|     15894 |         168 |
|     15966 |         374 |
+-----------+-------------+
183 rows in set (0.01 sec)

Info

NULL = NULL no se evalúa como verdadero en SQL estándar. Cuando una comparación involucra NULL, el resultado puede ser desconocido; por eso IS NULL y IS NOT NULL son operadores específicos para este caso.

Cierre

La cláusula WHERE convierte una tabla completa en un conjunto de filas relevante. Dominar igualdad, desigualdad, rangos, pertenencia, patrones y NULL te permite escribir consultas más precisas y seguras.

Como regla práctica, diseña filtros explícitos, valida condiciones destructivas con SELECT, y considera el impacto de funciones, comodines y expresiones regulares sobre los índices. En el siguiente artículo abordaremos Lógica condicional con CASE, una herramienta clave para transformar valores dentro de tus consultas.