Saltar al contenido principal
SQL y analíticaLección interactiva6 min de lectura

LEFT JOIN vs INNER JOIN: cuál usar y por qué cambia tu resultado

Por Pedro RodríguezPublicado Actualizado

Haces un JOIN entre clientes y pedidos y, de pronto, faltan clientes en el resultado. No se perdieron: tu consulta los descartó. Aquí ves por qué pasa, cuándo conviene cada tipo de JOIN y cómo evitar el error que hace que un LEFT JOIN se comporte como un INNER JOIN. Todo se ejecuta aquí mismo, con una base de ejemplo del blog.

¿Cuál es la diferencia entre INNER JOIN y LEFT JOIN?

Un JOIN une dos tablas buscando filas que coincidan en una columna. La diferencia está en qué pasa con las filas que no coinciden:

TipoFilas sin pareja de la izquierdaFilas sin pareja de la derecha
INNER JOINSe descartanSe descartan
LEFT JOINSe conservan, con NULL a la derechaSe descartan

La base de ejemplo del blog tiene diez clientes y catorce pedidos. Hay tres detalles que van a importar: Gabriela y Julián no tienen ningún pedido, y el pedido 114 se registró sin cliente (customer_id en NULL).

INNER JOIN: solo lo que tiene pareja en las dos tablas

Cuenta los pedidos de cada cliente con INNER JOIN. Ejecuta la consulta:

base: E-commerce (base de ejemplo del blog) · Ctrl + Enter para ejecutar
El resultado aparece aquí.

Salen 8 clientes. Gabriela y Julián no aparecen, porque no tienen ningún pedido con el que emparejarse. Si tu pregunta era "¿cuántos pedidos tiene cada cliente?", acabas de perder dos clientes sin darte cuenta.

LEFT JOIN: conserva todas las filas de la izquierda

Cambia solo la palabra JOIN por LEFT JOIN:

base: E-commerce (base de ejemplo del blog) · Ctrl + Enter para ejecutar
El resultado aparece aquí.

Ahora salen los 10 clientes y Gabriela y Julián muestran 0. Fíjate en que contamos o.order_id y no *: con COUNT(*) una fila rellena con NULL contaría como 1 pedido.

¿Cómo encuentro lo que no tiene pareja?

Un LEFT JOIN más IS NULL sobre la tabla de la derecha deja solo las filas sin pareja. Es la forma clásica de preguntar "clientes sin pedidos":

base: E-commerce (base de ejemplo del blog) · Ctrl + Enter para ejecutar
El resultado aparece aquí.

Aquí el WHERE o.order_id IS NULL es correcto: queremos justo las filas que quedaron con NULL. Si prefieres otra forma de hacerlo sin riesgos con NULL, mira nuestra lección de NOT IN con NULL.

¿Por qué mi LEFT JOIN se comporta como un INNER JOIN?

Es el error más común. Quieres los clientes con su número de pedidos completados, incluidos los que no tienen ninguno, y filtras en el WHERE:

base: E-commerce (base de ejemplo del blog) · Ctrl + Enter para ejecutar
El resultado aparece aquí.

Solo salen 6 clientes. Los que no tenían pedidos completados desaparecieron, justo los que el LEFT JOIN debía conservar. Pasa porque, después del JOIN, esos clientes tienen NULL en o.status, y NULL = 'completada' no es verdadero, así que el WHERE los descarta. Es como si hubieras escrito un INNER JOIN.

La solución es mover la condición al ON, que se evalúa mientras se hace la unión:

base: E-commerce (base de ejemplo del blog) · Ctrl + Enter para ejecutar
El resultado aparece aquí.

Vuelven los 10 clientes. Bruno, Gabriela, Isabel y Julián salen con 0 completados. Isabel sí tiene un pedido, pero está cancelado, así que no cuenta.

¿Qué cambia si empiezo desde la otra tabla?

El "lado izquierdo" es la tabla que escribes después de FROM. Si partimos de los pedidos y les unimos el cliente, el pedido sin cliente es el que se queda sin pareja:

base: E-commerce (base de ejemplo del blog) · Ctrl + Enter para ejecutar
El resultado aparece aquí.

Salen los 14 pedidos, y el 114 trae NULL en el nombre. Con INNER JOIN serían 13: ese pedido, que tiene dinero asociado, desaparecería del reporte.

INNER JOIN, LEFT JOIN y cuándo usar cada uno

SituaciónUsa
Solo te interesan las filas que existen en las dos tablasINNER JOIN
Quieres todas las filas de una tabla aunque no tengan parejaLEFT JOIN
Buscas filas sin pareja ("clientes sin compras")LEFT JOIN con IS NULL
Filtras columnas de la tabla de la derecha y quieres conservar las filas sin parejaLEFT JOIN con el filtro en el ON

¿Qué te preguntan sobre esto en una entrevista de SQL?

Casi siempre es la misma pregunta con distinto disfraz: "lista todos los clientes con el total que gastaron, incluyendo los que no gastaron nada". Quien usa INNER JOIN pierde a los clientes sin compras, y quien usa LEFT JOIN pero filtra en el WHERE los pierde igual. Explicar por qué pasa, con el ejemplo del NULL = 'completada', muestra que entiendes el orden en que SQL evalúa la consulta.

Inténtalo tú mismo

Escribe una consulta que muestre a todos los clientes con el total que gastaron en pedidos completados. A los que no gastaron nada debe salirles 0 (usa COALESCE). Llama gastado a la columna del total y ordena por nombre.

base: E-commerce (base de ejemplo del blog) · Ctrl + Enter para ejecutar
El resultado aparece aquí.

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 la cláusula JOIN y sobre las expresiones con NULL; estándar SQL, lógica de tres valores. Revisado por Pedro Rodríguez. Se revisa cada trimestre.

Únete a la comunidad de The Analyst Hub

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.