Saltar al contenido
null.sql · devschool

Valores NULL en SQL

Lección 4 de 22 · 12 min de lectura · Actualizado el

En esta lección
  1. Qué es NULL (y qué no es)
  2. IS NULL e IS NOT NULL
  3. Por qué = NULL no funciona
  4. La lógica de tres valores
  5. NULL en operaciones y concatenaciones
  6. COALESCE, IFNULL y NULLIF
  7. NULL en funciones de agregación
  8. NULL al ordenar
  9. La trampa de NOT IN con NULL
  10. Cuándo permitir NULL
  11. Errores frecuentes
  12. Resumen

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:

  • NULL no es 0. Una nota de 0 es un suspenso; una nota NULL significa que todavía no se ha puesto.
  • NULL no es '' (texto vacío). Un email '' es un email que alguien guardó en blanco; un email NULL es que no se sabe.
  • NULL no 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);
idnombreemailtelefononota
1Ireneirene@correo.es6001112228.50
2HugoNULL6003334446.00
3Sofíasofia@correo.esNULLNULL
4MarioNULL4.25
5Laralara@correo.es600555666NULL

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;
abc
NULLNULLNULL

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 NULL como iguales, MySQL tiene el operador <=> (a <=> b) y el estándar tiene IS 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:

ABA AND BA OR B
VerdaderoDesconocidoDesconocidoVerdadero
FalsoDesconocidoFalsoDesconocido
DesconocidoDesconocidoDesconocidoDesconocido

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;
nombrenota
Mario4.25
SELECT nombre, nota FROM alumnos WHERE NOT (nota < 5);
nombrenota
Irene8.50
Hugo6.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;
nombrenota
SofíaNULL
Mario4.25
LaraNULL

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 CONCAT cambia según el sistema. En MySQL, CONCAT('Tel: ', telefono) también devuelve NULL si algún argumento es NULL. En PostgreSQL y SQLite, CONCAT trata el NULL como texto vacío y devolvería 'Tel: '. En MySQL, CONCAT_WS(separador, ...) sí se salta los NULL.

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;
nombrecontacto
Ireneirene@correo.es
Hugo600333444
Sofíasofia@correo.es
Mario
Laralara@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;
nombreemail
Ireneirene@correo.es
Hugosin email
Sofíasofia@correo.es
Mariosin email
Laralara@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;
alumnoscon_notasumamediamedia_con_ceros
5318.756.253.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 los NULL como 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, SUM devuelve NULL, no 0. Un total de ventas de un día sin pedidos sale NULL. Por eso es habitual escribir COALESCE(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:

SistemaORDER BY nota (ASC)ORDER BY nota DESC
MySQL, MariaDB, SQLiteNULL al principioNULL al final
PostgreSQL, OracleNULL al finalNULL 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
nombrenota
Mario4.25
Hugo6.00
Irene8.50
SofíaNULL
LaraNULL

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 NULL para 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 NULL cuando 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 -1 para decir “no hay”: se cuelan en las medias y los filtros.
  • Evita mezclar '' y NULL para lo mismo, como en el email de Mario. Elige una forma (normalmente NULL) y úsala siempre.

Las restricciones como NOT NULL o DEFAULT se explican en claves y restricciones.

Errores frecuentes

  • Escribir = NULL o <> NULL: siempre da desconocido y no devuelve filas. Usa IS NULL e IS NOT NULL.
  • Olvidar las filas NULL en una condición negativa: WHERE nota <> 10 no incluye a quienes no tienen nota.
  • Usar IFNULL en PostgreSQL: no existe. COALESCE funciona en todos.
  • Sumar columnas que pueden ser NULL: precio + envio da NULL si falta el envío. Usa precio + COALESCE(envio, 0).

Resumen

Quieres…Escribe
Filas sin valorWHERE col IS NULL
Filas con valorWHERE col IS NOT NULL
Sustituir NULL (estándar)COALESCE(col, valor)
Sustituir NULL (MySQL/SQLite)IFNULL(col, valor)
Convertir un valor en NULLNULLIF(col, '')
Evitar dividir entre cerox / 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

[SQL] La tabla notas tiene 4 filas: 8, NULL, 4 y NULL en la columna nota. ¿Qué devuelve esta consulta?
SELECT COUNT(*), COUNT(nota), AVG(nota)
FROM notas;

[SQL] ¿Qué devuelve esta consulta?
SELECT nombre FROM alumnos
WHERE email = NULL;

[SQL] ¿Qué devuelve COALESCE(NULL, NULL, 'b', 'c')?

[SQL] La columna nota vale 8, NULL, 4 y NULL en cuatro filas. ¿Cuántas filas devuelve WHERE nota <> 8?
SELECT id FROM notas
WHERE nota <> 8;

¿Te ha quedado claro? Márcala y verás tu progreso en el explorador.