SQL IS NULL e IS NOT NULL
Lección 2.4 · Tiempo de lectura: ~6 min · Tareas de práctica ↓
IS NULL e IS NOT NULL son la única forma fiable de filtrar valores ausentes en SQL. En esta lección verás por qué WHERE column = NULL no encuentra nada, cómo encontrar filas con valor y sin él, y cómo NULL saca filas en silencio de las condiciones con NOT, <> y NOT IN. Los ejemplos usan la tabla rental de la base de datos Sakila: tiene 16044 filas, y return_date es NULL en las películas que aún no se han devuelto.
Por qué = NULL no encuentra nada
NULL significa «el valor es desconocido». Cualquier comparación con un valor desconocido también es desconocida: return_date = NULL no es verdadero ni falso, es UNKNOWN. WHERE solo conserva las filas en las que la condición es TRUE, así que la consulta no devuelve nada:
SELECT rental_id, rental_date, return_date
FROM rental
WHERE return_date = NULL;
Resultado: ninguna fila, aunque 183 alquileres no tienen fecha de devolución.
Lo mismo ocurre con <>, >, < y cualquier otro operador de comparación.
IS NULL
IS NULL es una comprobación especial que es TRUE cuando falta el valor:
SELECT rental_id, rental_date, return_date
FROM rental
WHERE return_date IS NULL;
Resultado: 183 filas, los alquileres cuyas películas siguen sin devolverse.
IS NULL se combina con otras condiciones como cualquier comparación:
SELECT rental_id, rental_date, return_date
FROM rental
WHERE customer_id = 554 AND return_date IS NULL;
Resultado: una fila, el alquiler 14098 del 2005-08-21: el cliente 554 todavía tiene esa película.
IS NOT NULL
IS NOT NULL es lo contrario: TRUE cuando la columna tiene un valor.
SELECT rental_id, rental_date, return_date
FROM rental
WHERE return_date IS NOT NULL;
Resultado: 15861 filas. Junto con los 183 alquileres sin fecha de devolución, son las 16044 filas de la tabla.
NULL queda fuera de una condición y de su NOT
Parece natural que una condición y su NOT dividan la tabla en dos. Con NULL no es así. Compara dos consultas:
SELECT rental_id, return_date
FROM rental
WHERE return_date >= '2005-08-01';
Resultado: 8207 filas.
SELECT rental_id, return_date
FROM rental
WHERE NOT (return_date >= '2005-08-01');
Resultado: 7654 filas. 8207 + 7654 = 15861, no 16044: para las 183 filas sin fecha de devolución ambas condiciones son UNKNOWN, y NOT UNKNOWN sigue siendo UNKNOWN.
Para conservar esas filas, pídelas de forma explícita con OR ... IS NULL:
SELECT rental_id, return_date
FROM rental
WHERE return_date >= '2005-08-01' OR return_date IS NULL;
Resultado: 8390 filas = 8207 + 183.
La trampa de NOT IN
NOT IN es una cadena de comparaciones <> unidas con AND. Si la lista contiene NULL, una de ellas siempre es UNKNOWN y ninguna fila pasa:
SELECT title, language_id
FROM film
WHERE language_id NOT IN (2, 3);
Resultado: 1000 filas, todas las películas.
SELECT title, language_id
FROM film
WHERE language_id NOT IN (2, NULL);
Resultado: ninguna fila, porque language_id <> NULL es UNKNOWN para todas las películas.
Nadie escribe NULL a mano en una lista, pero más adelante en el curso la lista saldrá de una columna, y basta un solo NULL para vaciar el resultado. Antes de usar NOT IN, asegúrate de que los valores no pueden ser NULL.
Mostrar un valor en lugar de NULL
COALESCE devuelve el primero de sus argumentos que no es NULL. Es útil para mostrar un valor legible en el resultado:
SELECT rental_id, rental_date, COALESCE(return_date, 'not returned')
FROM rental
WHERE customer_id = 554 AND rental_date >= '2005-08-21';
Resultado: 4 alquileres; el alquiler 14098 muestra «not returned». Sin nombre, la columna lleva como título la propia expresión.
Esto es MySQL. En PostgreSQL y SQL Server los dos argumentos deben ser del mismo tipo, así que allí la fecha se convierte primero en texto. COALESCE y otras funciones se ven en el módulo de funciones.
Conclusiones clave:
- Cualquier comparación con NULL (
=,<>,>,<) da UNKNOWN, yWHEREdescarta esas filas. - Usa
IS NULLpara encontrar filas sin valor eIS NOT NULLpara encontrar filas con valor; ambas se combinan conANDyOR. - Una condición y su
NOTjuntos no cubren las filas en las que la columna es NULL; añadeOR column IS NULLpara conservarlas. NOT INno devuelve ninguna fila si la lista contiene NULL.COALESCE(column, value)muestra un valor de sustitución en lugar de NULL.
Preguntas frecuentes
¿Por qué WHERE column = NULL no devuelve filas?
Una comparación con NULL es UNKNOWN, no TRUE, y WHERE solo conserva las filas TRUE. Usa WHERE column IS NULL.
¿IS NOT NULL es lo mismo que NOT (column = NULL)?
No. column = NULL es UNKNOWN, y NOT UNKNOWN también es UNKNOWN, así que NOT (column = NULL) tampoco encuentra nada. IS NOT NULL es TRUE para cada fila que tiene un valor.
¿Se puede combinar IS NULL con AND y OR?
Sí, como cualquier otra condición: WHERE customer_id = 554 AND return_date IS NULL encuentra las películas que un cliente todavía tiene, y OR return_date IS NULL añade a otra condición las filas sin valor.
Preguntas de entrevista
¿Por qué las consultas SQL usan IS NULL en lugar de = NULL?
NULL significa un valor desconocido, y comparar cualquier cosa con un valor desconocido da UNKNOWN, no TRUE ni FALSE. WHERE solo conserva las filas en las que la condición es TRUE, así que = NULL nunca encuentra nada. IS NULL es una prueba aparte que devuelve TRUE o FALSE.
¿Por qué NOT IN puede devolver un resultado vacío?
x NOT IN (a, b) significa x <> a AND x <> b. Si la lista contiene NULL, x <> NULL es UNKNOWN para cada fila, todo el AND no puede ser TRUE y no se devuelve ninguna fila. Ocurre cuando la lista sale de una subconsulta cuya columna tiene valores NULL.
¿Cómo se conservan las filas con NULL en un filtro?
Añade el caso NULL de forma explícita: WHERE return_date >= '2005-08-01' OR return_date IS NULL. Si no, las filas con NULL quedan descartadas tanto por la condición como por su negación.