SQL JOIN: consultas a varias tablas de datos

Una sentencia JOIN de SQL (término inglés para “unión”) designa toda operación en bases de datos relacionales que permite realizar consultas en varias bases de datos. Las sentencias JOIN combinan datos guardados en diferentes tablas y los presentan de forma filtrada en una tabla de resultados.

El principio de las sentencias SQL JOIN se basa en la operación homónima del álgebra relacional, una combinación entre producto cartesiano y selección. Mediante la selección del tipo de JOIN y de la definición de una condición de selección, el usuario puede establecer qué datos de las tablas originales aparecerán en la tabla de resultados.

A continuación, te informamos sobre los fundamentos matemáticos de SQL JOIN, comparamos diferentes tipos de JOIN y te mostramos con ejemplos prácticos cómo aplicar estas sentencias en las consultas a las bases de datos con SQL.

Consejo

Este artículo requiere conocer ciertos conceptos sobre el modelo relacional de bases de datos, concretamente en lo que a relaciones, tuplas, atributos o claves se refiere. En nuestro artículo general sobre bases de datos relacionales encuentras más información.

¿Cómo funcionan las sentencias SQL JOIN?

El principio básico de un SQL JOIN puede entenderse mejor si partimos de las operaciones que la componen. El fundamento de todo JOIN son las siguientes operaciones de álgebra relacional:

  • Producto cartesiano
  • Selección

El producto cartesiano

El producto cartesiano es una operación de la teoría de conjuntos en la que dos o más conjuntos se combinan entre sí. En el modelo de base de datos relacional se utiliza el producto cartesiano para interconectar conjuntos de tuplas en la forma de una tabla. El resultado de esta operación es otro conjunto de tuplas ordenadas, donde cada tupla está compuesta por un elemento de cada conjunto inicial.

En álgebra relacional se utiliza el símbolo de la multiplicación (×) como operador para el producto cartesiano.

Veamos un ejemplo:

El producto cartesiano A × B de ambos conjuntos A = {x, y, z} y B = {1, 2, 3} es:

A × B = {(x,1), (x,2), (x,3), (y,1), (y,2), (y,3), (z,1), (z,2), (z,3)}

Este cálculo puede ilustrarse con el siguiente gráfico:

Es importante señalar el orden de formación de los pares. El producto cartesiano A × B no se corresponde, por ejemplo, con el conjunto del producto cartesiano de B × A.

A × B = {(x,1), (x,2), (x,3), (y,1), (y,2), (y,3), (z,1), (z,2), (z,3)}

B × A = {(1,x), (1,y), (1,z), (2,x), (2,y), (2,z), (3,x), (3,y), (3,z)}

En la terminología SQL, una operación en la que el producto cartesiano resulta de dos tablas se denomina CROSS JOIN. En la práctica, las sentencias CROSS JOIN no se utilizan muy a menudo porque el conjunto resultante (intersección) se presenta sin filtrar.

La selección

Por selección se entiende la operación del álgebra relacional que permite seleccionar unas tuplas determinadas de un conjunto inicial y mostrarlas como conjunto de resultados. Para establecer qué tuplas constituirán este conjunto se utiliza una expresión relacional. El resultado de la selección es, por lo tanto, un conjunto de tuplas que cumplen la condición de la selección definida en esta expresión relacional. Como operador se utiliza la letra griega sigma (σ) y la operación se plasma de la siguiente manera:

σF (R)

El espaciador “F” corresponde a la expresión relacional, una fórmula de predicados lógicos que define la condición de la selección. “R” hace referencia al volumen de datos que ha de seleccionarse. También puede utilizarse la notación linear R[F].

Para formular las condiciones de la selección debe recurrirse a los operadores relacionales habituales, como son el símbolo de igual (=), más que (>) o menor que (<).

Te explicamos la selección por medio de un ejemplo extraído del texto sobre el modelo relacional. La siguiente tabla muestra datos personales ficticios que las empresas pueden requerir de sus empleados. Para cada empleado se recogen el número personal (e_ID), los apellidos y el nombre (apellidos, nombre), el número de la seguridad social (n° SS), la dirección (calle, n°, código postal, municipio), así como el número del vehículo de la empresa que se le ha asignado (coche_ID).

Tabla: Empleados                
e_ID 1 er apellido 2º apellido nombre n° SS calle CP municipio coche_ID
1 García Fernández Antonio 32 12345678 12 Calle Principal 1 11111 Villarriba 3
2 García García Josefa 28 87654321 49 Calle Iglesia 2 22222 Villabajo 1
3 Expósito Hernández Gonzalo 25 09122598 46 Plaza Mercado 3 33333 Campoarriba 1
4 Casas González Antonia 23 17083912 78 Calle Grande 4 44444 Campoabajo 2

Si queremos filtrar la tabla “Empleados” de manera que solo se muestren aquellos que utilicen el coche de empresa con el coche_ID 1, puedes proceder así:

σcoche_ID=1(Empleados)

En este caso, se hace una llamada a las tuplas en las que el valor de la columna coche_ID es igual a 1.

El resultado se recoge en la siguiente tabla:

Tabla: Empleados (selección)                
e_ID 1 er apellido 2º apellido nombre n° SS calle CP municipio coche_ID
2 García García Josefa 28 87654321 49 Calle Iglesia 2 22222 Villabajo 1
3 Expósito Hernández Gonzalo 25 09122598 46 Plaza Mercado 3 33333 Campoarriba 1

En el lenguaje de bases de datos SQL se definen las condiciones de selección con ayuda del comando WHERE.

SELECT * FROM Empleados WHERE Empleados.coche_ID = 1;

Si una tupla cumple con la condición coche_ID=1, deben emitirse los valores de todas las columnas.

Nota

En la sintaxis SQL, el asterisco (*) representa a todas las columnas de una tabla.

Combinación de producto cartesiano y selección

Los diferentes tipos de JOIN combinan el producto cartesiano con una condición de selección. Para explicar una operación de bases de datos de tal índole, reducimos la tabla “Empleados” (por claridad) a cuatro columnas. A esta añadimos la tabla “Vehículos” en la que se guarda información sobre los vehículos de la empresa.

Ambas tablas están vinculadas entre sí por una relación de claves externas. La clave primaria de la tabla “Vehículos” (coche_ID) funciona como clave externa en la tabla “Empleados”.

Tabla: Empleados        
e_ID 1 er apellido 2º apellido nombre coche_ID
1 García Fernández Antonio 3
2 García García Josefa 1
3 Expósito Hernández Gonzalo 1
4 Casas González Antonia 2
Tabla: Vehículos          
coche_ID marca modelo matrícula fabricación ITV
1 VW Caddy 1234 TGB 2016 43452
2 Opel Astra 9876 ZBU 2010 43689
3 BMW X6 5847 LOG 2017 43344
Nota

El reparto de la información en diferentes bases de datos es un concepto básico del modelo relacional de bases de datos. En nuestro artículo sobre la normalización de bases de datos relacionales te explicamos las ventajas de este diseño de bases de datos, así como su realización.

Si se quieren combinar ambas tablas y seleccionar las tuplas relevantes, deben combinarse las operaciones de bases de datos explicadas anteriormente:

σcoche_ID=coche_ID(Empleados × Vehículos)

Primero se formará el producto cartesiano Empleados × Vehículos. El resultado (provisional) es un CROSS JOIN, es decir, una tabla de resultados en la que cada tupla de la tabla “Empleados” se combina con cada tupla de la tabla “Automóviles”.

Tabla: Producto cartesiano “Empleados” × “Vehículos”                    
e_ID 1 er apellido 2º apellido nombre empleados.coche_ID vehículos.coche_ID marca modelo matrícula fabricación ITV
1 García Fernández Antonio 3 1 VW Caddy 1234 TGB 2016 18.12.2018
1 García Fernández Antonio 3 2 Opel Astra 9876 ZBU 2010 12.08.2019
1 García Fernández Antonio 3 3 BMW X6 5847 LOG 2017 01.09.2018
2 García García Josefa 1 1 VW Caddy 1234 TGB 2016 18.12.2018
2 García García Josefa 1 2 Opel Astra 9876 ZBU 2010 12.08.2019
2 García García Josefa 1 3 BMW X6 5847 LOG 2017 01.09.2018
3 Expósito Hernández Gonzalo 1 1 VW Caddy 1234 TGB 2016 18.12.2018
3 Expósito Hernández Gonzalo 1 2 Opel Astra 9876 ZBU 2010 12.08.2019
3 Expósito Hernández Gonzalo 1 3 BMW X6 5847 LOG 2017 01.09.2018
4 Casas González Antonia 2 1 VW Caddy 1234 TGB 2016 18.12.2018
4 Casas González Antonia 2 2 Opel Astra 9876 ZBU 2010 12.08.2019
4 Casas González Antonia 2 3 BMW X6 5847 LOG 2017 01.09.2018

A continuación, se seleccionan las tuplas en las que el coche_ID de la tabla “Vehículos” coincide con el coche_ID de la tabla “Empleados”. La condición de selección es, por lo tanto, que la clave externa de la tabla “Empleados” se corresponda con la clave primaria de la tabla “Vehículos”.

Como resultado (final) se obtiene una tabla que combina ambas tablas sin redundancias.

Tabla: JOIN sobre “Empleados” y “Vehículos”                    
e_ID 1 er apellido 2º apellido nombre empleados.coche_ID vehículos.coche_ID marca modelo matrícula fabricación ITV  
1 García Fernández Antonio 3 3 BMW X6 5847 LOG 2017 01.09.2018
2 García García Josefa 1 1 VW Caddy 1234 TGB 2016 18.12.2018
3 Expósito Hernández Gonzalo 1 1 VW Caddy 1234 TGB 2016 18.12.2018
4 Casas González Antonia 2 2 Opel Astra 9876 ZBU 2010 12.08.2019

Como combinación de producto cartesiano y selección, las sentencias JOIN de SQL agrupan ambas operaciones en una conjunta. Como operador se utiliza el símbolo de la pajarita (⋈).

Por lo tanto, se aplica:

σcoche_ID=coche_ID(Empleados × Vehículos) := Empleados⋈ código_vehículo=código_vehículoVehículos

La operación σcoche_ID=coche_ID(Empleados × Vehículos) se corresponde con un JOIN en las tablas “Empleados” y “Vehículos” con la condición coche_ID=coche_ID.

Transferida a la sintaxis SQL, la operación presentada anteriormente se correspondería con la siguiente sentencia:

SELECT * FROM Empleados INNER JOIN Vehículos ON Empleados.coche_ID = Vehículos.coche_ID;

INNER JOIN es una de las sentencias JOIN más importantes utilizada en el marco de las consultas a las bases de datos. Aun así, en ocasiones son necesarios algunos tipos de sentencias JOIN especiales para lograr el resultado deseado.

Tipos de SQL JOIN

En el modelo relacional de bases de datos se utilizan diferentes tipos de sentencias JOIN de SQL que permiten realizar consultas en un grupo de tablas. El requisito para ello es que las tablas seleccionadas estén vinculadas entre sí por medio de relaciones de claves externas.

Entre los tipos de sentencias JOIN de SQL más importantes se encuentran:

  • INNER JOIN: INNER JOIN hace referencia a una forma filtrada de CROSS JOIN en la que solo se incluyen en el conjunto resultante las tuplas de las tablas originarias que cumplen la condición de selección definida por el usuario.
     
  • OUTER JOIN: OUTER JOIN es una extensión de INNER JOIN. El conjunto de resultados de una sentencia OUTER JOIN contiene las tuplas de que cumplen la condición de selección definida por el usuario, así como el resto de tuplas de la primera tabla, de la segunda o de ambas tablas. Las sentencias OUTER JOIN pueden clasificarse en 3 tipos: LEFT OUTER JOIN, RIGHT OUTER JOIN o FULL OUTER JOIN.
Consejo

Puedes encontrar una descripción detallada sobre INNER JOIN y OUTER JOIN en los artículos de nuestra guía que dan cobertura a dichas sentencias.

Las diferencias entre INNER JOIN y los diferentes tipos de OUTER JOIN pueden ilustrarse con diagramas de Venn. El siguiente gráfico es una representación visual de los tipos de JOIN presentados:

Independientemente de la diferenciación entre INNER JOIN y OUTER JOIN, las sentencias SQL JOIN pueden clasificarse en los siguientes tipos:

  • EQUI JOIN
  • NON EQUI JOIN
  • SELF JOIN

Las sentencias INNER JOIN y OUTER JOIN pueden implementarse en forma de EQUI JOIN y NON EQUI JOIN. Los diferentes ejemplos de JOIN especificados hasta ahora están representados por EQUI JOIN y este tipo se caracteriza por el hecho de que solo permite el signo de igual como operador relacional (=).

La condición de selección de una sentencia EQUI JOIN siempre es, por lo tanto, la igualdad de los valores de las columnas.

En principio, las sentencias JOIN no se limitan (al igual que la selección en el álgebra relacional) a la igualdad de las columnas. Los posibles operadores relacionales son:

Operador relacional Significado
= Igual
Menor que
Mayor que
Menor o igual
Mayor o igual
<>  Diferente
!= Diferente

Desde SQL-92, el lenguaje de bases de datos ofrece con la palabra clave USING una forma abreviada para sentencias EQUI JOIN que requiere que las columnas afectadas tengan el mismo nombre, lo que no siempre ocurre.

El siguiente ejemplo muestra dos sentencias SQL diferentes que dan lugar al mismo resultado. En la primera sentencia se define la condición JOIN con ayuda de la palabra clave ON. En la segunda se utiliza la versión abreviada con la clave USING.

SELECT * FROM Empleados INNER JOIN Vehículos ON Empleados.coche_ID = Vehículos.coche_ID;
SELECT * FROM Empleados INNER JOIN Vehículos USING coche_ID;

Por el contrario, las sentencias NON EQUI JOIN excluyen operaciones en base a la igualdad de las columnas. Así, se permiten todas las operaciones relacionales a excepción de las que van acompañadas del signo igual (=).

Nota

Dado que las relaciones en las bases de datos relacionales se definen generalmente por medio de la igualdad de las claves primarias y externas, las sentencias NON EQUI JOIN tienen una importancia secundaria en el modelo de bases de datos relacional debido a que, al igual que las sentencias CROSS JOIN, dan lugar a menudo a muchos registros de resultados.

Después de todo, una sentencia SELF JOIN es un tipo especial de sentencia SQL JOIN en la que la tabla de una base de datos está vinculada a sí misma. En principio, cada tipo de JOIN puede ejecutarse como SELF JOIN.

Si dos tablas están unidas por columnas homónimas, se puede hablar de NATURAL JOIN. Una sentencia de este tipo que utiliza una palabra clave homónima se implementa normalmente como INNER JOIN, pero en este tipo de JOIN no están definidas las sentencias NATURAL JOIN, sino que la posibilidad es recurrir a las sentencias NATURAL LEFT OUTER JOIN o NATURAL RIGHT OUTER JOIN.

Dado que el vínculo en las sentencias NATURAL JOIN se logra utilizando columnas del mismo nombre, los valores en cuestión no se ofrecen por partida doble en el conjunto de resultados, sino que se fusionan en una columna conjunta. Puedes encontrar ejemplos de sentencias INNER JOIN y OUTER JOIN en otros artículos de nuestra guía.