Pregunta 1¿Qué devuelve SELECT * FROM customer WHERE email = NULL;?
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.
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.
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.
-- 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)
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.
-- 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');
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.
Verificación de conocimientos
Responde cada pregunta una a una.
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?