Valores NULL en SQL
En esta lección
NULL es la forma que tiene SQL de decir “no sé este dato”. Un alumno que aún no tiene nota, un cliente que no dio su teléfono, un empleado sin departamento asignado. NULL se comporta de forma distinta a cualquier otro valor y causa muchos resultados “misteriosos”: filas que desaparecen, sumas vacías, medias que no cuadran. En esta lección aprenderás a buscarlo, a entender por qué se comporta así y a sustituirlo cuando te estorba.
Qué es NULL (y qué no es)
NULL significa ausencia de valor: el dato es desconocido o no se aplica. No es un valor “vacío” de ningún tipo:
NULLno es0. Una nota de 0 es un suspenso; una notaNULLsignifica que todavía no se ha puesto.NULLno es''(texto vacío). Un email''es un email que alguien guardó en blanco; un emailNULLes que no se sabe.NULLno es el texto'NULL', que son cuatro letras.
Como las tablas del curso no tienen valores NULL, en esta lección usaremos una tabla de alumnos de un curso de programación:
CREATE TABLE alumnos (
id INT PRIMARY KEY,
nombre VARCHAR(50) NOT NULL,
email VARCHAR(100),
telefono VARCHAR(15),
nota DECIMAL(4, 2)
);
INSERT INTO alumnos (id, nombre, email, telefono, nota) VALUES
(1, 'Irene', 'irene@correo.es', '600111222', 8.50),
(2, 'Hugo', NULL, '600333444', 6.00),
(3, 'Sofía', 'sofia@correo.es', NULL, NULL),
(4, 'Mario', '', NULL, 4.25),
(5, 'Lara', 'lara@correo.es', '600555666', NULL);
| id | nombre | telefono | nota | |
|---|---|---|---|---|
| 1 | Irene | irene@correo.es | 600111222 | 8.50 |
| 2 | Hugo | NULL | 600333444 | 6.00 |
| 3 | Sofía | sofia@correo.es | NULL | NULL |
| 4 | Mario | NULL | 4.25 | |
| 5 | Lara | lara@correo.es | 600555666 | NULL |
Fíjate en Mario: su email es un texto vacío '', que no es lo mismo que el NULL de Hugo.
IS NULL e IS NOT NULL
Para buscar filas sin valor se usa IS NULL:
SELECT nombre FROM alumnos
WHERE email IS NULL;
| nombre |
|---|
| Hugo |
Mario no sale: su email es '', no NULL.
IS NOT NULL devuelve las filas que sí tienen valor. WHERE email IS NOT NULL devolvería a Irene, Sofía, Mario y Lara.
Por qué = NULL no funciona
Lo natural sería escribir WHERE email = NULL. Pero esta consulta no devuelve ninguna fila, ni da error:
SELECT nombre FROM alumnos
WHERE email = NULL; -- ✗ siempre vacío
La razón es lógica. Si NULL significa “no lo sé”, la pregunta “¿el email de Hugo es igual a algo desconocido?” no tiene respuesta. Ni sí ni no: desconocido. Y cualquier comparación con NULL da desconocido, que SQL también representa como NULL:
SELECT NULL = NULL AS a, NULL <> 5 AS b, 5 > NULL AS c;
| a | b | c |
|---|---|---|
| NULL | NULL | NULL |
Ni siquiera NULL = NULL es verdadero: dos datos desconocidos no tienen por qué ser iguales. WHERE solo deja pasar las filas cuya condición es verdadera, así que las que dan desconocido se descartan. Por eso existe un operador especial, IS NULL, que sí responde sí o no.
Nota: si necesitas comparar dos columnas tratando dos
NULLcomo iguales, MySQL tiene el operador<=>(a <=> b) y el estándar tieneIS NOT DISTINCT FROM, que admiten PostgreSQL y SQLite (desde 3.39), pero no MySQL.
La lógica de tres valores
En SQL una condición no tiene dos resultados posibles, sino tres: verdadero, falso y desconocido (NULL). AND, OR y NOT siguen estas reglas:
| A | B | A AND B | A OR B |
|---|---|---|---|
| Verdadero | Desconocido | Desconocido | Verdadero |
| Falso | Desconocido | Falso | Desconocido |
| Desconocido | Desconocido | Desconocido | Desconocido |
Y NOT desconocido sigue siendo desconocido. Piensa en “no lo sé”: si una parte de un OR ya es verdadera, el resultado es verdadero valga lo que valga la otra; si una parte de un AND ya es falsa, el resultado es falso.
La consecuencia práctica es que las filas con NULL no están ni en una condición ni en su contraria:
SELECT nombre, nota FROM alumnos WHERE nota < 5;
| nombre | nota |
|---|---|
| Mario | 4.25 |
SELECT nombre, nota FROM alumnos WHERE NOT (nota < 5);
| nombre | nota |
|---|---|
| Irene | 8.50 |
| Hugo | 6.00 |
Entre las dos consultas suman tres alumnos de cinco. Sofía y Lara no aparecen en ninguna, porque NULL < 5 es desconocido y NOT desconocido también. Si quieres incluirlas, dilo de forma explícita:
-- Alumnos suspensos o todavía sin nota
SELECT nombre, nota FROM alumnos
WHERE nota < 5 OR nota IS NULL;
| nombre | nota |
|---|---|
| Sofía | NULL |
| Mario | 4.25 |
| Lara | NULL |
NULL en operaciones y concatenaciones
Cualquier operación aritmética con NULL da NULL. Si no sabes cuánto vale la nota, tampoco sabes cuánto vale la nota más uno:
SELECT nombre, nota + 1 AS nota_subida
FROM alumnos; -- Irene 9.50, Hugo 7.00, Mario 5.25; Sofía y Lara, NULL
Con los textos pasa lo mismo al concatenar con || (el operador estándar):
SELECT nombre, 'Tel: ' || telefono AS contacto
FROM alumnos;
Irene, Hugo y Lara obtienen 'Tel: 600...', pero Sofía y Mario, que no tienen teléfono, obtienen NULL: no se sabe cómo termina el texto.
Cuidado: la función
CONCATcambia según el sistema. En MySQL,CONCAT('Tel: ', telefono)también devuelveNULLsi algún argumento esNULL. En PostgreSQL y SQLite,CONCATtrata elNULLcomo texto vacío y devolvería'Tel: '. En MySQL,CONCAT_WS(separador, ...)sí se salta losNULL.
COALESCE, IFNULL y NULLIF
Estas funciones sirven para sustituir NULL por otro valor, o al revés.
COALESCE: el primero que no sea NULL
COALESCE(a, b, c, ...) devuelve el primer argumento que no es NULL. Es estándar y funciona en todos los sistemas:
COALESCE(nota, 0) mostraría 0.00 para Sofía y Lara, y la nota real para los demás. Con varios argumentos es aún más práctico. Por ejemplo, la forma de contacto de cada alumno: el email si lo tiene; si no, el teléfono; y si tampoco, un texto fijo:
SELECT nombre, COALESCE(email, telefono, 'sin contacto') AS contacto
FROM alumnos;
| nombre | contacto |
|---|---|
| Irene | irene@correo.es |
| Hugo | 600333444 |
| Sofía | sofia@correo.es |
| Mario | |
| Lara | lara@correo.es |
Mario sale con un contacto vacío: su email es '', que no es NULL.
IFNULL: la versión de dos argumentos
IFNULL(valor, sustituto) es como COALESCE con solo dos argumentos. Existe en MySQL y SQLite, pero no en PostgreSQL (ni en SQL Server, que tiene ISNULL). Si quieres que tu SQL funcione en todas partes, usa COALESCE.
SELECT nombre, IFNULL(telefono, '-') AS telefono FROM alumnos; -- MySQL y SQLite
NULLIF: convertir un valor en NULL
NULLIF(a, b) hace lo contrario: devuelve NULL si a y b son iguales, y a si no lo son. Sirve para tratar como “sin dato” valores que en realidad lo son, como el email vacío de Mario:
SELECT nombre, COALESCE(NULLIF(email, ''), 'sin email') AS email
FROM alumnos;
| nombre | |
|---|---|
| Irene | irene@correo.es |
| Hugo | sin email |
| Sofía | sofia@correo.es |
| Mario | sin email |
| Lara | lara@correo.es |
NULLIF(email, '') convierte el '' de Mario en NULL, y después COALESCE pone el texto. Otro uso clásico es evitar una división entre cero: total / NULLIF(unidades, 0) devuelve NULL en lugar de un error cuando no hay unidades.
NULL en funciones de agregación
Las funciones de agregación ignoran los NULL, salvo COUNT(*), que cuenta filas:
SELECT
COUNT(*) AS alumnos,
COUNT(nota) AS con_nota,
SUM(nota) AS suma,
ROUND(AVG(nota), 2) AS media,
ROUND(AVG(COALESCE(nota, 0)), 2) AS media_con_ceros
FROM alumnos;
| alumnos | con_nota | suma | media | media_con_ceros |
|---|---|---|---|---|
| 5 | 3 | 18.75 | 6.25 | 3.75 |
COUNT(*)cuenta 5 filas;COUNT(nota), solo las 3 que tienen nota.AVG(nota)es 18.75 / 3 = 6.25: la media de los que tienen nota.AVG(COALESCE(nota, 0))es 18.75 / 5 = 3.75: cuenta losNULLcomo ceros.
¿Cuál es la correcta? Depende de la pregunta. Si Sofía y Lara aún no han hecho el examen, 6.25. Si no se presentaron y eso cuenta como cero, 3.75. SQL no lo puede saber: lo decides tú.
Cuidado: si no hay ninguna fila,
SUMdevuelveNULL, no0. Un total de ventas de un día sin pedidos saleNULL. Por eso es habitual escribirCOALESCE(SUM(importe), 0), como verás en JOIN.
En cambio, GROUP BY y DISTINCT tratan todos los NULL como un mismo grupo: GROUP BY telefono daría una fila para los alumnos sin teléfono.
NULL al ordenar
¿Dónde van los NULL en un ORDER BY? Depende del sistema:
| Sistema | ORDER BY nota (ASC) | ORDER BY nota DESC |
|---|---|---|
| MySQL, MariaDB, SQLite | NULL al principio | NULL al final |
| PostgreSQL, Oracle | NULL al final | NULL al principio |
Para decidir tú, PostgreSQL y SQLite (desde 3.30) admiten NULLS FIRST y NULLS LAST. MySQL no, pero tiene un truco: ordenar primero por nota IS NULL, que vale 0 para las filas con nota y 1 para las demás:
SELECT nombre, nota FROM alumnos
ORDER BY nota IS NULL, nota; -- en PostgreSQL o SQLite: ORDER BY nota NULLS LAST
| nombre | nota |
|---|---|
| Mario | 4.25 |
| Hugo | 6.00 |
| Irene | 8.50 |
| Sofía | NULL |
| Lara | NULL |
La trampa de NOT IN con NULL
Si la lista de un NOT IN contiene un NULL, la consulta no devuelve nada:
SELECT nombre FROM alumnos
WHERE id NOT IN (1, NULL);
Resultado: ninguna fila. id NOT IN (1, NULL) equivale a id <> 1 AND id <> NULL. La segunda parte es desconocida para todas las filas y, según la tabla de tres valores, verdadero AND desconocido es desconocido. Nadie pasa el filtro.
Ocurre sobre todo cuando la lista sale de una consulta con alguna fila NULL. Cómo evitarlo con NOT EXISTS lo verás en subconsultas. IN, en cambio, funciona sin problemas: id IN (1, NULL) devuelve a Irene.
Cuándo permitir NULL
Al crear una tabla, cada columna admite NULL salvo que pongas NOT NULL. Decide columna a columna:
NOT NULLpara lo imprescindible: el nombre de un alumno, el importe de un pedido, la fecha de una reserva. Una fila sin ese dato no tiene sentido.- Permitir
NULLcuando el dato puede no existir o no conocerse todavía: la nota antes del examen, la fecha de baja de un socio en activo, el segundo apellido. - No uses valores “mágicos” como una nota de
-1para decir “no hay”: se cuelan en las medias y los filtros. - Evita mezclar
''yNULLpara lo mismo, como en el email de Mario. Elige una forma (normalmenteNULL) y úsala siempre.
Las restricciones como NOT NULL o DEFAULT se explican en claves y restricciones.
Errores frecuentes
- Escribir
= NULLo<> NULL: siempre da desconocido y no devuelve filas. UsaIS NULLeIS NOT NULL. - Olvidar las filas
NULLen una condición negativa:WHERE nota <> 10no incluye a quienes no tienen nota. - Usar
IFNULLen PostgreSQL: no existe.COALESCEfunciona en todos. - Sumar columnas que pueden ser
NULL:precio + enviodaNULLsi falta el envío. Usaprecio + COALESCE(envio, 0).
Resumen
| Quieres… | Escribe |
|---|---|
| Filas sin valor | WHERE col IS NULL |
| Filas con valor | WHERE col IS NOT NULL |
Sustituir NULL (estándar) | COALESCE(col, valor) |
Sustituir NULL (MySQL/SQLite) | IFNULL(col, valor) |
Convertir un valor en NULL | NULLIF(col, '') |
| Evitar dividir entre cero | x / NULLIF(y, 0) |
NULL al final (MySQL) | ORDER BY col IS NULL, col |
NULL al final (PostgreSQL/SQLite) | ORDER BY col NULLS LAST |
Recuerda la idea clave: NULL significa “no lo sé”, y cualquier cosa que hagas con algo que no sabes da, a su vez, “no lo sé”. En la siguiente lección aprenderás a ordenar resultados con ORDER BY.
Pon a prueba lo que has aprendido
¿Te ha quedado claro? Márcala y verás tu progreso en el explorador.