NOT IN con NULL: por qué tu consulta devuelve 0 filas y cómo arreglarla
Escribes un NOT IN que debería devolver cuatro clientes y la consulta responde con una tabla vacía. No es un error del motor: es cómo SQL trata a NULL. Aquí lo rompes y lo arreglas tú mismo, con una base de ejemplo del blog.
¿Qué pasa realmente con NOT IN y NULL?
Para SQL, NULL significa "valor desconocido". Preguntar si un cliente no está en una lista que contiene un valor desconocido no tiene respuesta segura: ese valor desconocido podría ser justo ese cliente. Por eso la comparación no da verdadero ni falso, da desconocido, y WHERE solo deja pasar lo verdadero.
En esta base de ejemplo del blog tenemos diez clientes y sus pedidos. Fíjate en el último pedido (order_id 114): se registró sin cliente, con customer_id en NULL.
Pruébalo: la consulta que devuelve 0 filas
Queremos los clientes que no tienen ningún pedido completado. Ejecuta esta consulta tal como está:
¿Por qué da 0 filas si hay clientes sin pedidos?
Porque la subconsulta incluye un NULL (el pedido sin cliente). Para el cliente 2 (Bruno), SQL evalúa una cadena de comparaciones con AND, y la última, contra NULL, es desconocida. Un desconocido dentro de un AND arrastra todo el resultado a desconocido, así que WHERE no lo deja pasar. Pasa lo mismo con cada cliente.
¿Cómo se arregla? Dos formas
Opción 1: filtrar los NULL de la subconsulta
Agrega AND customer_id IS NOT NULL dentro de la subconsulta. La consulta ya viene corregida: solo ejecútala.
Opción 2 (recomendada): NOT EXISTS
NOT EXISTS pregunta "¿hay alguna fila que cumpla esto?" y no se confunde con NULL. Además suele ser igual de rápido.
NOT IN, NOT EXISTS y LEFT JOIN: comparación
| Técnica | ¿Seguro con NULL? | Cuándo usarla |
|---|---|---|
NOT IN | No | Solo si la columna no admite NULL |
NOT EXISTS | Sí | Casi siempre. Es la opción por defecto |
LEFT JOIN ... IS NULL | Sí | Cuando además necesitas columnas del otro lado |
¿Cómo aparece esto en una entrevista de SQL?
Es una pregunta clásica: te piden "clientes sin compras" y la trampa es que la tabla de pedidos tiene un cliente en NULL. Quien responde con NOT IN obtiene una tabla vacía y no sabe por qué. Si lo explicas como arriba, ya mostraste que entiendes la lógica de tres valores de SQL.
Inténtalo tú mismo
Ahora te toca a ti. Escribe una consulta que devuelva los productos que nunca se vendieron en un pedido completado. Tienes las tablas products, order_items y orders. Usa lo que acabas de aprender.
FUENTES Y VERIFICACIÓN
Todas las consultas de este artículo se ejecutaron contra la base de ejemplo del blog antes de publicarse. Referencias: documentación oficial de SQLite sobre el operador IN y NULL; estándar SQL, lógica de tres valores. Revisado por Pedro Rodríguez. Se revisa cada trimestre.
Deja tu correo y te llega la invitación al Discord y el newsletter semanal con lo nuevo en datos e IA.
Solo lo usamos para el enlace al Discord y el newsletter. Puedes darte de baja cuando quieras.