La idea
WHERE es un portero. Para cada fila de la tabla hace una pregunta de sí o no, armada con tus
condiciones, y solo pasan las filas que reciben un sí definitivo. La fila no se cambia, no se mueve y
no se compara con sus vecinas. Se prueba sola y se conserva o se queda fuera.
Suena a dos resultados, pero SQL tiene tres. Una prueba puede ser verdadera, falsa o desconocida, y
lo desconocido aparece en cuanto interviene un NULL. WHERE conserva solo lo verdadero. Casi todos los
errores de filtrado que encontrarás vienen de olvidar la tercera respuesta o de confundir el orden en
que se combinan AND y OR.
Figura 1
WHERE prueba cada fila por separado, y AND exige que pasen las dos pruebas
| order_id | channel | status |
|---|---|---|
| 1003 | marketplace | completed |
| 1004 | marketplace | completed |
| 1005 | web | completed |
| 1006 | marketplace | cancelled |
| 1007 | marketplace | completed |
| 1008 | web | completed |
| order_id | channel | status |
|---|---|---|
| 1003 | marketplace | completed |
| 1004 | marketplace | completed |
| 1007 | marketplace | completed |
- Seis filas de
orders. La pregunta:WHERE channel = 'marketplace' AND status = 'completed'. La base de datos se la hace a cada fila por separado, como si las demás no existieran. - Primera prueba:
channel = 'marketplace'. Los pedidos 1005 y 1008 son de la web, así que fallan. Pasan cuatro filas. - Segunda prueba:
status = 'completed'. El pedido 1006 pasó la primera prueba, pero fue cancelado.ANDnecesita que ambas respuestas sean sí, así que falla. - Quedan tres filas. Las filas conservadas se copian sin cambios al resultado:
WHEREsolo decide quién se queda, nunca edita un valor.
Por qué existe
Harbor & Pine tiene unos 12,000 pedidos y nadie los lee todos. Necesitan los reembolsos del mes pasado,
los clientes de negocio en Texas, los productos sin costo. WHERE es la forma de reducir la tabla a las
filas que le importan a la pregunta, antes de contar, sumar u ordenar nada. Filtrar pronto también
importa para la velocidad: cada paso posterior tiene menos filas con las que trabajar.
Sin él tendrías que exportarlo todo y filtrar a ojo en una hoja de cálculo, y la respuesta cambiaría en
cuanto cambiaran los datos. Una cláusula WHERE es la pregunta escrita, así que puedes volver a
ejecutarla la próxima semana y obtener el mismo tipo de respuesta.
Piensa en una cláusula WHERE como una frase que podrías leerle en voz alta a un colega: "pedidos del
marketplace que se completaron". Si no puedes decirla con palabras simples, probablemente la condición
no es lo que querías. Ese hábito atrapa la mayoría de los errores antes de ejecutar nada.
Cómo funciona por dentro
Cada fila pasa por la condición de forma independiente:
- La base de datos toma una fila y evalúa cada comparación con los valores de esa fila.
- Combina los resultados con
ANDyORen una sola respuesta: verdadero, falso o desconocido. - Solo lo verdadero conserva la fila. Falso y desconocido la descartan.
Esa última regla es toda la historia del NULL. Un NULL significa "valor no conocido", así que
unit_cost = 503.50 es desconocido cuando el costo es NULL, y también lo es unit_cost <> 503.50. La
fila falla ambas pruebas.
Figura 2
Comparar con NULL da desconocido, y WHERE conserva solo lo verdadero
| product_id | name | unit_cost |
|---|---|---|
| 101 | Vale Velvet Loveseat | NULL |
| 102 | Alder Oak Coffee Table | 503.50 |
| 103 | Orchard Rattan Dining Chair | 429.87 |
| product_id | name |
|---|---|
| 101 | Vale Velvet Loveseat |
- ¿Qué productos no tienen costo registrado? El producto 101 sí: su
unit_costesNULL, es decir, desconocido. WHERE unit_cost = NULLpregunta: ¿un desconocido es igual a otro desconocido? Nadie puede decirlo. La respuesta no es verdadera ni falsa sino desconocida, yWHEREconserva solo lo verdadero.- Para el 101 es desconocido, y para el 102 y el 103 es falso. Ninguna fila es verdadera, así que la consulta no devuelve nada, sin ningún error.
IS NULLes otra prueba. Responde un sí o no claro: ¿falta este valor? La fila 101 es un sí, y se conserva.
La solución es una prueba específica: IS NULL e IS NOT NULL preguntan "¿falta el valor?" y siempre
responden sí o no. La misma lógica esconde una segunda trampa. WHERE referral_source <> 'search'
descarta en silencio a todos los clientes sin fuente de referencia, porque para ellos la comparación es
desconocida. Si quieres incluir a esos clientes, dilo: OR referral_source IS NULL.
Cómo se combina lo desconocido
La lógica de tres valores tiene unas reglas que vale la pena conocer. unknown AND false es falso,
porque un solo falso basta para fallar. unknown AND true es desconocido. unknown OR true es
verdadero, porque un solo verdadero basta para pasar. unknown OR false es desconocido. Y NOT unknown
sigue siendo desconocido, por eso NOT (unit_cost = 503.50) sigue perdiendo las filas con NULL. Rara vez
las calculas a mano. Solo recuerda que un NULL únicamente se rescata con algo verdadero.
AND se une con más fuerza que OR
Como la multiplicación antes que la suma, AND se evalúa antes que OR. Este filtro
WHERE channel = 'marketplace' OR status = 'completed' AND channel = 'web'
se lee como channel = 'marketplace' OR (status = 'completed' AND channel = 'web'). Cuando querías
decir otra cosa, el resultado es erróneo y ningún error te avisa. Usa paréntesis siempre que una
condición mezcle los dos. IN ('web', 'app') es una forma ordenada de escribir varios OR sobre la
misma columna.
Fechas en un timestamp
order_date es un timestamp, no una fecha simple. WHERE order_date <= '2024-03-31' significa "hasta la
medianoche con que empieza el 31 de marzo", así que se pierden todos los pedidos de ese día. Escribe un
rango semiabierto: order_date >= '2024-03-01' AND order_date < '2024-04-01'. Incluye todo marzo y
sirve para cualquier mes, sin importar su duración.
Patrones
LIKE '%@gmail.com' busca texto por patrón: % representa cualquier cantidad de caracteres y _
exactamente uno. LIKE normal distingue mayúsculas y minúsculas en la mayoría de las bases de datos, así
que pasa la columna a minúsculas primero o usa ILIKE donde exista. Un patrón con % al inicio tiene
que leer todos los valores, así que resérvalo para las preguntas que lo necesiten.
Dónde está WHERE
WHERE corre justo después de FROM, sobre las filas sin procesar. Eso tiene dos efectos prácticos. No
puede ver los alias que defines en SELECT, porque todavía no existen. Y no puede filtrar por un total
como COUNT(*) > 10, porque tampoco existen totales todavía. Las condiciones sobre totales van en
HAVING, que verás en el capítulo 4.
Errores comunes
"WHERE columna = NULL encuentra los valores que faltan"
No devuelve nada, y sin ningún error, por eso duele. La comparación es desconocida para todas las filas.
Usa IS NULL. Si un filtro que debería coincidir con algo devuelve cero filas, revisa si interviene un
NULL antes que cualquier otra cosa.
"Distinto conserva todo lo que no es igual"
Conserva todo lo que se sabe que es diferente. Una fila con NULL no es igual ni distinta, así que
desaparece tanto de = 'x' como de <> 'x'. Los dos resultados no suman la tabla entera. Cuenta las
filas antes y después, y busca la diferencia.
"Un filtro no puede cambiar los valores de mis filas"
Cierto, y es una regla útil: WHERE conserva o descarta filas completas, nunca las edita. Si un valor se
ve mal en la salida, el problema está en SELECT o en los datos, no en el filtro. Un filtro sí puede
cambiar qué filas ve un agregado, así que un total puede cambiar cuando agregas una condición.
Ponte a prueba
Una pregunta. Al responderla, la lección queda marcada en el mapa; nunca bloquea un nivel.
No del todo. Nada se contradice. AND se une con más fuerza que OR, así que el filtro son dos grupos independientes, y cada fila solo tiene que pasar uno de ellos.Prueba otra respuesta.
No del todo. OR conserva una fila que pasa cualquiera de los lados. El pedido 1006 pasa channel = 'marketplace' y también se conserva.Prueba otra respuesta.
No del todo. La condición no se aplica a toda la lista. AND se ejecuta primero, así que se lee channel = 'marketplace' OR (status = 'completed' AND channel = 'web').Prueba otra respuesta.
Correcto. AND se evalúa antes que OR. El 1006 cumple la prueba de marketplace y el 1008 cumple la agrupada. Usa paréntesis para que se vea.
Lección hecha: ya está marcada en el mapa.