Aprende leyendo en orden

WHERE en profundidad ③ — IS NULL e IN para filtrado por NULL y conjuntos

El tercer artículo de WHERE en profundidad — filtrado por NULL y por conjuntos. Cubre la lógica de tres valores, IS NULL / IS NOT NULL, IN / NOT IN y la trampa de NOT IN + NULL, todo sobre un dataset customer cargado desde CSV.

Datos que usaremos — la tabla customer (con NULLs)

El tercer artículo de WHERE en profundidad cubre NULL y filtrado basado en conjuntos. Trabajaremos con una tabla customer (8 filas) cargada desde CSV, donde las columnas age / email / country tienen cada una filas con NULL (valor desconocido). En tablas del mundo real es normal que las columnas no obligatorias mezclen NULLs — "email no registrado", "country dejado en blanco", etc.

Los cinco ejercicios de este artículo recorren, por orden: la forma correcta de obtener NULLs (IS NULL / IS NOT NULL), la coincidencia con lista de candidatos (IN / NOT IN) y por último la trampa fácil de pasar por alto al usar NOT IN contra datos que contienen NULLs.

Antes de los ejercicios, confirma las definiciones de columnas de la tabla customer y una muestra de los datos.

① Ejecuta PRAGMA table_info(customer); para comprobar nombres de columnas, tipos y claves primarias.

② Ejecuta SELECT * FROM customer LIMIT 5; para previsualizar las primeras 5 filas. Fíjate en las celdas que son NULL.

Editor SQL

Ejecutar una consulta para ver el resultado

NULL y la lógica de tres valores — true, false, unknown

En la mayoría de lenguajes de programación una condición es TRUE o FALSE — dos opciones. SQL añade un estado más: NULL (desconocido). Esto se llama lógica de tres valores. NULL no significa "el valor está vacío"; significa "el valor no se conoce". Incluso NULL = NULL se evalúa como NULL (desconocido) — comparar dos desconocidos deja el resultado desconocido.

WHERE condition solo conserva las filas donde la condición es TRUE. Tanto las filas NULL como las FALSE quedan excluidas. Una vez que esa regla encaja, verás por qué WHERE email = NULL siempre vuelve vacío.

Lógica de tres valores en SQL
TRUEFALSENULL(desconocido)
El resultado de la evaluación de una condición es uno de estos tres. WHERE conserva una fila solo cuando el resultado es TRUE — FALSE y NULL se tratan ambos como "excluido".
Lógica de tres valores — evaluación TRUE / FALSE / NULL
ExpresiónSe evalúa como¿Conservada por WHERE?name = 'Alice'(cuando name es Alice)TRUE○ conservadaname = 'Bob'(cuando name es Alice)FALSE× excluidaemail = NULL(cuando email es NULL)NULL× excluida(no es TRUE)email IS NULL(cuando email es NULL)TRUE○ conservada
WHERE conserva solo las filas donde la condición es TRUE. Las comparaciones que involucran NULL se evalúan como NULL, y NULL no es TRUE, así que la fila queda excluida.

Por qué `email = NULL` no devuelve nada

La comparación email = NULL siempre devuelve NULL (desconocido) cuando cualquiera de los lados es NULL. 'unknown' = NULL y NULL = NULL se evalúan ambos como NULL. WHERE solo conserva las filas donde la condición es TRUE, así que las condiciones NULL quedan excluidas, dejando 0 filas.

Para obtener NULLs, necesitas la sintaxis dedicada column IS NULL / column IS NOT NULL. Estas no hacen comparación de igualdad — comprueban directamente si el valor es NULL — y el resultado es siempre TRUE o FALSE.

"¿Cero clientes no se han dado de baja?"

Al sacar "el conteo de clientes que no se han dado de baja (deleted_at IS NULL)", una vez escribí SELECT COUNT(*) FROM user WHERE deleted_at = NULL; y el resultado volvió como 0.

En realidad había miles de usuarios activos, pero deleted_at = NULL siempre se evalúa como NULL (desconocido) y queda excluido por WHERE, así que sin importar cuántos usuarios existieran el resultado era siempre 0. Es un error fácil cuando empiezas con SQL — adquiere el hábito de usar `IS NULL` / `IS NOT NULL` para cada comprobación de NULL.

IS NULL e IS NOT NULL — obtener valores desconocidos

Para obtener filas donde un valor es NULL (desconocido), usa `column IS NULL`. Para obtener filas que no son NULL, usa column IS NOT NULL. Recuerda nunca usar `= NULL` o `<> NULL` y esquivarás la trampa de la lógica de tres valores.

Como muestra el código de abajo, la sintaxis es solo IS en lugar de = — pero el resultado es completamente diferente. = NULL no devuelve nada; IS NULL devuelve correctamente las filas NULL.

En qué se diferencian `= NULL` e `IS NULL`
WHERE email = NULLWHERE email IS NULLNULL = NULL→ NULLemail IS NULL→ TRUENULL no es TRUE,así que siempre excluidaLas filas TRUE se conservan,así que las filas NULL pasanResultado: 0 filasResultado: 4 filas(Bob / Dave / Frank / Henry)
= NULL siempre se evalúa como NULL (desconocido), así que WHERE devuelve 0 filas. IS NULL comprueba directamente NULL y devuelve TRUE o FALSE.
-- 1) MAL: = NULL no obtiene nada (siempre NULL = excluida)
SELECT name, email FROM customer WHERE email = NULL;
-- Resultado: 0 filas

-- 2) BIEN: IS NULL obtiene las filas NULL
SELECT name, email FROM customer WHERE email IS NULL;
-- Resultado: 4 filas (Bob / Dave / Frank / Henry)

-- 3) Obtiene las filas no-NULL
SELECT name, email FROM customer WHERE email IS NOT NULL;
-- Resultado: 4 filas (Alice / Carol / Eve / Grace)

Imagina que atención al cliente quiere "una lista de clientes sin email registrado para enviarles una solicitud de registro". (Una vez lo ejecutes correctamente, aparecerá la explicación.)

① De customer, saca las columnas name y email.

② Filtra a las filas donde `email` sea NULL.

③ Confirma que el resultado son 4 filas (Bob / Dave / Frank / Henry, todos con email NULL).

Editor SQL

Ejecutar una consulta para ver el resultado

Imagina que la entrega de anuncios dirigidos quiere "clientes con age y email registrados", ordenados por mayor age primero.

① De customer, saca las columnas name, age y email.

② Filtra a las filas donde ni `age` ni `email` sean NULL.

③ Ordena por `age` descendente.

④ Confirma que el resultado son 3 filas (Eve 42 / Grace 35 / Alice 30).

Editor SQL

Ejecutar una consulta para ver el resultado

IN y NOT IN — coincidir contra una lista de candidatos

Cuando quieres comprobar si el valor de una columna está en una lista de candidatos — "country es Japan, US o UK" — eso es IN. Escribir column IN (value1, value2, ...) devuelve filas donde la columna coincide con alguno de los candidatos. Significa lo mismo que column = value1 OR column = value2 OR column = value3; la gente suele elegir IN solo por legibilidad.

Añadir NOT IN devuelve filas que no coinciden con ninguno de los candidatos.

Cómo funciona `IN` — coincidir contra una lista de candidatos
valor de countryIN ('Japan', 'US')¿Conservada por WHERE?JapanTRUE○ conservadaUSTRUE○ conservadaUKFALSE× excluidaItalyFALSE× excluidaNULLNULL(desconocido)× excluida(NULL no es TRUE)
IN comprueba si el valor coincide con alguno de los candidatos. Las filas donde la propia columna es NULL se evalúan como NULL tanto en IN como en NOT IN, así que quedan excluidas — para datos que contienen NULL, combina con IS NULL / IS NOT NULL.
-- 1) IN: coincide con cualquier candidato
SELECT name, country FROM customer
WHERE country IN ('Japan', 'US');

-- Mismo significado, escrito con OR
SELECT name, country FROM customer
WHERE country = 'Japan' OR country = 'US';

-- 2) NOT IN: no coincide con ninguno de los candidatos
SELECT name, country FROM customer
WHERE country NOT IN ('Japan');

Imagina la necesidad de "enviar un email de anuncio a clientes de Japan o US".

① De customer, saca las columnas name y country.

② Filtra a las filas donde `country` sea `'Japan'` o `'US'` (usa IN).

③ Confirma que el resultado son 5 filas (Alice Japan / Bob US / Carol Japan / Frank Japan / Grace US).

Editor SQL

Ejecutar una consulta para ver el resultado

La trampa de `NOT IN` + NULL

NOT IN ('Japan') parece coger "clientes cuyo country no es Japan", pero también excluye filas donde `country` es NULL. Eso es porque country NOT IN ('Japan') se evalúa internamente como country <> 'Japan' (no igual), y NULL <> 'Japan' devuelve NULL (desconocido). NULL no es TRUE, así que WHERE descarta la fila.

Llevándolo más lejos, escribir NOT IN ('Japan', NULL) — con un NULL dentro de la lista de candidatos — provoca que cada fila se evalúe como NULL y desaparezca. Al usar NOT IN contra una columna que pueda contener NULL, haz siempre explícito el manejo de NULL (column NOT IN (...) AND column IS NOT NULL) o reescribe la consulta en términos de IN.

Imagina la necesidad de "ofrecer una ventaja premium a los 2 clientes no-Japan más mayores".

① De customer, saca las columnas name, age y country.

② Filtra a las filas donde `country` no sea `'Japan'` (NOT IN).

③ Ordena por `age` descendente y toma solo las 2 primeras filas.

④ Confirma que el resultado son 2 filas (Grace 35 US / Henry 29 Italy). La razón por la que Eve (country NULL) queda excluida se explicará en la sección de resultado.

Editor SQL

Ejecutar una consulta para ver el resultado

Construyendo sobre la trampa del Ejercicio 4, imagina que quieres coger tanto "clientes confirmados que no viven en Japan" como "clientes cuyo country es desconocido".

① De customer, saca las columnas name, age y country.

② Incluye filas donde `country` no sea `'Japan'` más filas donde `country` sea NULL (unidas con OR).

③ Ordena por `age` descendente.

④ Confirma que el resultado son 5 filas (Eve 42 NULL / Grace 35 US / Henry 29 Italy / Dave 28 UK / Bob 25 US).

Editor SQL

Ejecutar una consulta para ver el resultado
QUIZ

Verificación de conocimientos

Responde cada pregunta una a una.

Pregunta 1¿Qué devuelve SELECT * FROM customer WHERE email = NULL;?

Pregunta 2¿Cuál de las siguientes describe correctamente el filtrado con IN?

Pregunta 3Ejecutando WHERE country NOT IN ('Japan') sobre una tabla customer donde la columna country contiene NULLs, ¿cómo se manejan las filas con country NULL?