Natural Join

El NATURAL JOIN es un tipo de JOIN que determina automáticamente la condición de unión basándose en los nombres de las columnas. MySQL busca todas las columnas que tengan exactamente el mismo nombre en ambas tablas y las usa como condición de igualdad. No necesitas escribir la cláusula ON.

Aunque puede parecer una forma conveniente de escribir menos SQL, el NATURAL JOIN es considerado una mala práctica por la mayoría de desarrolladores y guías de estilo SQL. En este artículo explicamos cómo funciona y por qué es arriesgado usarlo.

Sintaxis

SELECT columnas
FROM tabla1
NATURAL JOIN tabla2;

No hay ON. MySQL identifica las columnas con nombres idénticos en ambas tablas y las usa automáticamente como condición de unión.

Cómo funciona

Cuando escribes NATURAL JOIN, MySQL sigue estos pasos:

  1. Examina los esquemas de ambas tablas.
  2. Identifica todas las columnas que tienen exactamente el mismo nombre en ambas tablas.
  3. Genera internamente una condición ON que iguala esas columnas.
  4. Ejecuta un INNER JOIN con esa condición.

Las columnas comunes aparecen una sola vez en el resultado (no duplicadas).

Un ejemplo que parece funcionar

Supongamos que tenemos dos tablas simples donde la columna de unión tiene un nombre claro y único:

-- Esto funciona correctamente porque 'producto_id' es la
-- única columna compartida entre resenas y etiquetas_producto
SELECT
    r.producto_id,
    r.puntuacion,
    e.etiqueta
FROM resenas r
NATURAL JOIN etiquetas_producto e
WHERE r.producto_id = 1;

MySQL detecta que ambas tablas comparten la columna producto_id y la usa como condición de unión. El resultado muestra las reseñas del producto 1 combinadas con sus etiquetas. Funciona porque producto_id es la única columna con el mismo nombre en ambas tablas (aparte de id, que también comparten, lo que en realidad ya introduce un problema).

El problema fundamental

El NATURAL JOIN es frágil porque depende enteramente de los nombres de las columnas, y estos pueden cambiar o coincidir por accidente. Veamos qué pasa cuando intentamos un NATURAL JOIN entre productos y categorias:

-- ¿Qué columnas comparten productos y categorias?
-- Ambas tienen: id, nombre
-- Esto genera: ON productos.id = categorias.id AND productos.nombre = categorias.nombre
SELECT *
FROM productos
NATURAL JOIN categorias;
Empty set (0.00 sec)

El resultado está vacío. El motivo es que MySQL encuentra dos columnas con el mismo nombre: id y nombre. Genera internamente la condición ON productos.id = categorias.id AND productos.nombre = categorias.nombre. No existe ningún producto cuyo id coincida con el id de su categoría y cuyo nombre sea idéntico al nombre de la categoría, así que no hay resultados.

Lo que realmente queríamos era unir por categoria_id = id, pero NATURAL JOIN no puede adivinar eso. Solo mira nombres idénticos.

Otros problemas

El NATURAL JOIN tiene más problemas además del emparejamiento incorrecto. Si un desarrollador añade una nueva columna a una tabla y por casualidad le pone el mismo nombre que una columna de la otra tabla, todas las consultas NATURAL JOIN entre esas tablas cambiarán silenciosamente de comportamiento. No habrá error, simplemente los resultados serán diferentes.

Columnas genéricas como id, nombre, descripcion, fecha, estado o tipo son extremadamente comunes en cualquier base de datos. Es casi imposible diseñar un esquema donde estas columnas no coincidan accidentalmente entre tablas.

Además, la consulta no es autoexplicativa. Quien lea un NATURAL JOIN necesita conocer el esquema exacto de ambas tablas para entender qué condición se está aplicando. Con un JOIN ... ON explícito, la intención queda clara directamente en el SQL.

NATURAL JOIN vs JOIN explícito

Compara la claridad de ambos enfoques:

-- NATURAL JOIN: ¿qué condición usa? Hay que conocer el esquema
SELECT *
FROM pedidos
NATURAL JOIN clientes;
 
-- JOIN explícito: la condición es evidente
SELECT *
FROM pedidos p
INNER JOIN clientes cl ON p.cliente_id = cl.id;

El NATURAL JOIN entre pedidos y clientes usará las columnas id compartidas, lo que no producirá el resultado deseado (unirá donde pedidos.id = clientes.id en lugar de pedidos.cliente_id = clientes.id).

NATURAL LEFT JOIN y NATURAL RIGHT JOIN

MySQL también permite NATURAL LEFT JOIN y NATURAL RIGHT JOIN, que combinan el emparejamiento automático con la preservación de filas del LEFT o RIGHT JOIN:

-- No recomendado, pero existe
SELECT *
FROM productos
NATURAL LEFT JOIN resenas;

Estos tienen los mismos problemas que el NATURAL JOIN básico: dependen de coincidencias de nombres que pueden cambiar con el tiempo.

La cláusula USING como alternativa

Si quieres evitar escribir la cláusula ON completa pero manteniendo el control sobre qué columnas se usan, MySQL ofrece la cláusula USING:

-- Con ON (explícito)
SELECT p.id, p.fecha_pedido, cl.nombre
FROM pedidos p
JOIN clientes cl ON p.cliente_id = cl.id;
 
-- Con USING (cuando la columna tiene el mismo nombre en ambas tablas)
SELECT dp.pedido_id, dp.producto_id, p.nombre
FROM detalle_pedidos dp
JOIN productos p USING (id);

USING requiere que las columnas tengan el mismo nombre en ambas tablas, pero a diferencia de NATURAL JOIN, tú eliges explícitamente cuáles. Es más seguro que NATURAL JOIN porque no se ve afectado si se añaden nuevas columnas. Sin embargo, en la práctica, la cláusula ON sigue siendo la más utilizada porque funciona incluso cuando los nombres de columna no coinciden (como cliente_id vs id).

Recomendación

Evita NATURAL JOIN en código de producción. Usa siempre JOIN ... ON con la condición explícita. Es más largo de escribir, pero:

  • La intención es clara para cualquier persona que lea el código.
  • No se rompe si el esquema cambia.
  • Funciona con cualquier par de columnas, no solo con nombres idénticos.
  • Los errores son evidentes en lugar de silenciosos.

El NATURAL JOIN existe en MySQL por compatibilidad con el estándar SQL, pero hay consenso general en la comunidad de que es una funcionalidad que no debería usarse.

Con esto completamos la sección de JOINs. En la siguiente sección exploraremos las operaciones de conjunto: UNION, INTERSECT y EXCEPT, que permiten combinar los resultados de múltiples consultas.

Escrito por Eduardo Lázaro