Introducción
Muchos diseños de bases de datos separan la información en diferentes tablas según las relaciones entre puntos de datos específicos. Incluso en casos como este, es probable que alguien quiera recuperar información de más de una tabla a la vez.
Una forma común de acceder a datos de varias tablas en una operación de Lenguaje de Consulta Estructurado (SQL) es combinar tablas con una cláusula JOIN. Basándose en la operación de unión del álgebra relacional, una cláusula JOIN combina tablas independientes haciendo coincidir las filas de cada tabla que estén relacionadas entre sí. Normalmente, esta relación se basa en un par de columnas (una de cada tabla) que comparten valores, como la clave externa de una tabla y la clave principal de otra tabla a la que hace referencia la clave externa.
Esta guía explica cómo crear diversas consultas SQL que incluyen una cláusula JOIN. También muestra los diferentes tipos de cláusulas JOIN, cómo combinar datos de varias tablas y cómo crear alias en columnas para simplificar la escritura de operaciones JOIN.
Requisitos previos
Para seguir esta guía, necesitará una computadora con algún tipo de sistema de gestión de bases de datos relacionales (SGBDR) que utilice SQL. Las instrucciones y ejemplos de esta guía se han verificado en el siguiente entorno:
- Un servidor que ejecuta Ubuntu 20.04, con un usuario no root con privilegios administrativos y un firewall configurado con UFW
- MySQL está instalado y protegido en el servidor.
- También necesitará una base de datos con algunas tablas cargadas con datos de ejemplo que pueda usar para practicar las operaciones JOIN. Le recomendamos consultar la sección "Conectarse a MySQL y configurar una base de datos de ejemplo" a continuación para obtener más información sobre cómo conectarse al servidor MySQL y crear la base de datos de prueba utilizada en los ejemplos de esta guía.
Conexión a MySQL y configuración de una base de datos de ejemplo
Si su sistema de base de datos SQL se ejecuta en un servidor remoto, conéctese a su servidor mediante SSH desde su máquina local:
ssh sammy@your_server_ip
A continuación, abre la consola del servidor MySQL y sustituye Sami por tu nombre de usuario de MySQL:
mysql -u sammy -p
Crea una base de datos llamada joinsDB:
CREATE DATABASE joinsDB;
Si la base de datos se crea correctamente, recibirá el siguiente resultado:
Output
Query OK, 1 row affected (0.01 sec)Para seleccionar la base de datos joinsDB, ejecute la siguiente declaración USE:
USE joinsDB;Output
Database changedTras seleccionar joinsDB, cree varias tablas dentro de ella. Para los ejemplos de esta guía, imagine que dirige una fábrica y ha decidido registrar la información sobre su línea de producción, el equipo de ventas y las ventas de su empresa en una base de datos SQL. Comenzará con tres tablas, la primera de las cuales almacenará información sobre sus productos. Decide que esta primera tabla necesita tres columnas:
- ID de producto: El número de identificación de cada producto, expresado con el tipo de dato int. Esta columna actúa como clave principal de la tabla, lo que significa que cada valor actúa como un identificador único para la fila correspondiente. Dado que cada valor de una clave principal debe ser único, esta columna también tiene aplicada la restricción UNIQUE.
- productName: El nombre de cada producto se expresa utilizando el tipo de datos varchar con un máximo de 20 caracteres.
- Precio: El precio de cada producto, expresado en decimal. Esto especifica que cada valor de esta columna tiene un límite máximo de cuatro dígitos, dos de los cuales se ubican a la derecha de la coma decimal. Por lo tanto, el rango de valores permitidos en esta columna es de -99,99 a 99,99.
Cree una tabla llamada productos que tenga estas tres columnas:
CREATE TABLE products (
productID int UNIQUE,
productName varchar(20),
price decimal (4,2),
PRIMARY KEY (productID)
);La segunda tabla almacena información sobre los empleados del equipo de ventas de su empresa. Usted decide que esta tabla también necesita tres columnas:
- empID: Similar a la columna productID, esta columna contiene un número de identificación único para cada empleado del equipo de ventas, expresado como un tipo de dato int. Por lo tanto, esta columna tendrá una restricción UNIQUE y actuará como clave principal de la tabla team.
- empName: El nombre de cada vendedor expresado utilizando el tipo de datos varchar con un máximo de 20 caracteres.
- ProductSpecialty: A cada miembro de tu equipo de ventas se le asigna un producto como especialidad. Pueden vender cualquier producto de tu empresa, pero su enfoque principal se centra en el producto en el que se especializan. Para representar esto en la tabla, crea esta columna que contiene el valor de productID de cada producto en el que se especializa cada empleado.
Para garantizar que la columna productSpecialty contenga únicamente valores que representen números de ID de producto válidos, decide aplicar una restricción de clave externa a la columna que hace referencia a la columna productID de la tabla Products. Una restricción de clave externa es una forma de expresar una relación entre dos tablas que exige que los valores de la columna a la que se aplica existan en la columna a la que hace referencia. En la siguiente instrucción CREATE TABLE, la restricción FOREIGN KEY exige que cualquier valor añadido a la columna productSpecialty de la tabla team exista en la columna productID de la tabla Products.
Crea una tabla llamada Equipo con estas tres columnas:
CREATE TABLE team (
empID int UNIQUE,
empName varchar(20),
productSpecialty int,
PRIMARY KEY (empID),
FOREIGN KEY (productSpecialty) REFERENCES products (productID)
);
La última tabla que cree contendrá los registros de ventas de la empresa. Esta tabla tendrá cuatro columnas:
- ID de venta: Al igual que las columnas ID de producto y ID de emp, esta columna contiene un número de identificación único para cada venta, expresado como un tipo de dato entero. Esta columna también tiene una restricción UNIQUE para que pueda actuar como clave principal de la tabla de ventas.
- Cantidad: El número de unidades vendidas de cada producto se expresa con el tipo de dato int.
- ID del producto: El número de identificación del producto vendido, expresado como un int.
- Vendedor: Número de identificación del empleado que realizó la venta.
Al igual que con la columna productSpecialty de la tabla team, decide aplicar restricciones FOREIGN KEY a las columnas productID y salesperson. Esto garantiza que estas columnas solo contengan valores presentes en las columnas productID de la tabla products y empID de la tabla team, respectivamente.
Crea una tabla llamada Ventas con estas cuatro columnas:
CREATE TABLE sales (
saleID int UNIQUE,
quantity int,
productID int,
salesperson int,
PRIMARY KEY (saleID),
FOREIGN KEY (productID) REFERENCES products (productID),
FOREIGN KEY (salesperson) REFERENCES team (empID)
);Luego, cargue la tabla Productos con datos de muestra ejecutando la siguiente operación INSERT INTO:
INSERT INTO products
VALUES
(1, 'widget', 18.99),
(2, 'gizmo', 14.49),
(3, 'thingamajig', 39.99),
(4, 'doodad', 11.50),
(5, 'whatzit', 29.99);A continuación, cargue la tabla del equipo con datos de muestra:
INSERT INTO team
VALUES
(1, 'Florence', 1),
(2, 'Mary', 4),
(3, 'Diana', 3),
(4, 'Betty', 2);Cargue también la tabla de ventas con datos de muestra:
INSERT INTO sales
VALUES
(1, 7, 1, 1),
(2, 10, 5, 4),
(3, 8, 2, 4),
(4, 1, 3, 3),
(5, 5, 1, 3);Finalmente, imagine que su empresa realiza algunas ventas sin la intervención de ningún miembro del equipo de ventas. Para registrarlas, ejecute la siguiente operación para agregar tres filas a la tabla Ventas que no tengan un valor en la columna Vendedor:
INSERT INTO sales (saleID, quantity, productID)
VALUES
(6, 1, 5),
(7, 3, 1),
(8, 4, 5);Una vez hecho esto, estará listo para seguir el resto de la guía y comenzar a aprender cómo unir tablas en SQL.
Comprender la sintaxis de la operación JOIN
Las cláusulas JOIN se pueden usar en diversas sentencias SQL, incluyendo operaciones UPDATE y DELETE. Sin embargo, a modo de ejemplo, los ejemplos de esta guía utilizan consultas SELECT para demostrar su funcionamiento.
El siguiente ejemplo muestra la sintaxis general de una declaración SELECT que incluye una cláusula JOIN:
SELECT table1.column1, table2.column2
FROM table1 JOIN table2
ON search_condition;Esta sintaxis comienza con una instrucción SELECT que devuelve dos columnas de dos tablas distintas. Tenga en cuenta que, dado que las cláusulas JOIN comparan el contenido de más de una tabla, esta sintaxis de ejemplo especifica de qué tabla se seleccionará cada columna, precediendo el nombre de la columna con el nombre de la tabla y un punto. Esto se conoce como una referencia de columna completa.
Puede usar referencias de columna completas como estas en cualquier operación, pero técnicamente solo es necesario en operaciones donde dos columnas de tablas diferentes tienen el mismo nombre. Sin embargo, es recomendable usarlas al trabajar con varias tablas, ya que pueden facilitar la lectura y la comprensión de las operaciones JOIN.
Después de SELECT viene la cláusula FROM. En cualquier consulta, la cláusula FROM define el conjunto de datos que se debe buscar para obtener los datos deseados. La única diferencia es que la cláusula FROM consta de dos tablas separadas por la palabra clave JOIN. Una forma útil de planificar las consultas es recordar seleccionar las columnas que se devolverán de la tabla que se desea consultar.
Luego, existe una cláusula ON que explica cómo la consulta debe unir las dos tablas mediante la definición de una condición de búsqueda. Una condición de búsqueda es un conjunto de una o más declaraciones o expresiones que pueden evaluarse como "verdadero", "falso" o "desconocido" para una condición específica. Puede ser útil considerar la operación JOIN como la combinación de todas las filas de ambas tablas y la devolución de todas las filas para las que la condición de búsqueda de la cláusula ON se evalúa como "verdadero".
En una cláusula ON, suele ser conveniente incluir una condición de búsqueda que compruebe si dos columnas relacionadas (como la clave externa de una tabla y la clave principal de otra tabla a la que hace referencia la clave externa) tienen valores iguales. Esto se conoce a veces como una unión equitativa.
Como ejemplo de cómo equi puede unir datos coincidentes de varias tablas, ejecute la siguiente consulta con los datos de ejemplo que agregó anteriormente. Esto une las tablas Productos y Equipo con una condición de búsqueda que busca valores coincidentes en sus respectivas columnas ID de producto y Especialidad de producto. A continuación, devuelve el nombre de cada miembro del equipo de ventas, el nombre de cada producto en el que se especializa y el precio de dichos productos:
SELECT team.empName, products.productName, products.price
FROM products JOIN team
ON products.productID = team.productSpecialtyدر اینجا مجموعه نتایج این پرس و جو است:
Output
+----------+-------------+-------+
| empName | productName | price |
+----------+-------------+-------+
| Florence | widget | 18.99 |
| Mary | doodad | 11.50 |
| Diana | thingamajig | 39.99 |
| Betty | gizmo | 14.49 |
+----------+-------------+-------+
4 rows in set (0.00 sec)Para ilustrar cómo SQL combina estas tablas para formar este conjunto de resultados, analicemos el proceso con más detalle. Para ser claros, lo siguiente no explica exactamente cómo un sistema de gestión de bases de datos uniría dos tablas, pero puede ser útil considerar la operación JOIN como un procedimiento.
En primer lugar, la consulta imprime los productos de cada fila y columna de la primera tabla en la cláusula FROM:
JOIN Process Example
+-----------+-------------+-------+
| productID | productName | price |
+-----------+-------------+-------+
| 1 | widget | 18.99 |
| 2 | gizmo | 14.49 |
| 3 | thingamajig | 39.99 |
| 4 | doodad | 11.50 |
| 5 | whatzit | 29.99 |
+-----------+-------------+-------+JOIN Process Example
+-----------+-------------+-------+-------+----------+------------------+
| productID | productName | price | empID | empName | productSpecialty |
+-----------+-------------+-------+-------+----------+------------------+
| 1 | widget | 18.99 | 1 | Florence | 1 |
| 2 | gizmo | 14.49 | 4 | Betty | 2 |
| 3 | thingamajig | 39.99 | 3 | Diana | 3 |
| 4 | doodad | 11.50 | 2 | Mary | 4 |
| 5 | whatzit | 29.99 | | | |
+-----------+-------------+-------+-------+----------+------------------+JOIN Process Example
+----------+-------------+-------+
| empName | productName | price |
+----------+-------------+-------+
| Florence | widget | 18.99 |
| Mary | doodad | 11.50 |
| Diana | thingamajig | 39.99 |
| Betty | gizmo | 14.49 |
+----------+-------------+-------+
4 rows in set (0.00 sec)Usar uniones equi es la forma más común de unir tablas, pero otros operadores SQL como <, >, LIKE, NOT LIKE o incluso BETWEEN pueden usarse en la condición de búsqueda de la cláusula ON. Sin embargo, tenga en cuenta que usar condiciones de búsqueda más complejas puede dificultar la predicción de los datos que aparecerán en el conjunto de resultados.
En la mayoría de las implementaciones, se pueden unir tablas mediante cualquier conjunto de columnas que tengan lo que el estándar SQL denomina un tipo de datos "JOIN calificado". Esto significa que, en general, se puede unir una columna que contenga datos numéricos con cualquier otra columna que contenga datos numéricos, independientemente de los tipos de datos correspondientes. De igual forma, se puede unir cualquier columna que contenga valores de caracteres con cualquier otra columna que contenga datos de caracteres. Como se mencionó anteriormente, las columnas que se combinan para unir dos tablas suelen ser columnas que representan una relación entre ellas, como una clave externa y la clave principal de otra tabla a la que hace referencia.
Muchas implementaciones de SQL permiten unir columnas con el mismo nombre mediante la palabra clave USING en lugar de ON. La sintaxis para esta operación podría ser:
SELECT table1.column1, table2.column2
FROM table1 JOIN table2
USING (related_column);En esta sintaxis de ejemplo, la instrucción USING es equivalente a ON table1.related_column = table2.related_column;.
Dado que las ventas y los productos tienen una columna llamada productID, puede unirlas mediante la palabra clave USING. La siguiente instrucción realiza esto y devuelve el saleID de cada venta, el número de unidades vendidas, el nombre de cada producto vendido y su precio. Además, ordena el conjunto de resultados según el valor de saleID en orden ascendente:
SELECT sales.saleID, sales.quantity, products.productName, products.price
FROM sales JOIN products
USING (productID)
ORDER BY saleID;Output
+--------+----------+-------------+-------+
| saleID | quantity | productName | price |
+--------+----------+-------------+-------+
| 1 | 7 | widget | 18.99 |
| 2 | 10 | whatzit | 29.99 |
| 3 | 8 | gizmo | 14.49 |
| 4 | 1 | thingamajig | 39.99 |
| 5 | 5 | widget | 18.99 |
| 6 | 1 | whatzit | 29.99 |
| 7 | 3 | widget | 18.99 |
| 8 | 4 | whatzit | 29.99 |
+--------+----------+-------------+-------+
8 rows in set (0.00 sec)Al unir tablas, el sistema de base de datos a veces organiza las filas de maneras difíciles de predecir. Incluir una cláusula ORDER BY como esta puede ayudar a que los conjuntos de resultados sean más coherentes y legibles.
Unir más de dos mesas
Puede que en ocasiones necesite combinar datos de más de dos tablas. Puede unir cualquier número de tablas anidando cláusulas JOIN dentro de otras cláusulas JOIN. La siguiente sintaxis es un ejemplo de cómo se vería al unir tres tablas:
SELECT table1.column1, table2.column2, table3.column3
FROM table1 JOIN table2
ON table1.related_column = table2.related_column
JOIN table3
ON table3.related_column = table1_or_2.related_column;La cláusula FROM en esta declaración de ejemplo comienza uniendo la tabla 1 a la tabla 2. Después de esta cláusula ON, comienza una segunda JOIN que combina el conjunto inicial de tablas unidas con la tabla 3. Tenga en cuenta que la tercera tabla se puede unir a una columna de la primera o la segunda tabla.
Por ejemplo, imagine que desea saber cuánto generaron las ventas de su empleado, pero solo le interesan los registros de ventas que incluyen las ventas de un producto en el que el empleado se especializa.
Para obtener esta información, puede ejecutar la siguiente consulta. Esta consulta comienza uniendo las tablas Productos y Ventas mediante la coincidencia de sus respectivas columnas productID. A continuación, une la tabla Equipo con las dos primeras tablas haciendo coincidir cada fila del JOIN inicial con su columna productSpecialty. La consulta filtra los resultados con una cláusula WHERE para devolver solo las filas donde el empleado coincidente sea también la persona que realizó la venta. La consulta también incluye una cláusula ORDER BY que ordena los resultados finales en orden ascendente según el valor de la columna saleID:
SELECT sales.saleID,
team.empName,
products.productName,
(sales.quantity * products.price)
FROM products JOIN sales
USING (productID)
JOIN team
ON team.productSpecialty = sales.productID
WHERE team.empID = sales.salesperson
ORDER BY sales.saleID;
Output
+--------+----------+-------------+-----------------------------------+
| saleID | empName | productName | (sales.quantity * products.price) |
+--------+----------+-------------+-----------------------------------+
| 1 | Florence | widget | 132.93 |
| 3 | Betty | gizmo | 115.92 |
| 4 | Diana | thingamajig | 39.99 |
+--------+----------+-------------+-----------------------------------+
3 rows in set (0.00 sec)Hasta ahora, todos los ejemplos tenían un tipo de expresión JOIN: una unión interna. Continúe leyendo la siguiente sección para obtener una descripción general de las uniones internas, las uniones externas y sus diferencias.
Operaciones JOIN internas y externas
Existen dos tipos principales de instrucciones JOIN: uniones internas y externas. La diferencia entre estos dos tipos de uniones radica en los datos que devuelven. Las uniones internas devuelven solo las filas coincidentes de cada tabla unida, mientras que las uniones externas devuelven tanto las filas coincidentes como las no coincidentes.
La sintaxis y las consultas de ejemplo de las secciones anteriores utilizan sentencias INNER JOIN, aunque ninguna incluye la palabra clave INNER. La mayoría de las implementaciones de SQL tratan cada sentencia JOIN como una unión INNER, a menos que se indique explícitamente lo contrario.
Las consultas que especifican una unión externa combinan varias tablas y devuelven tanto las filas coincidentes como las no coincidentes. Esto puede ser útil para encontrar filas con valores faltantes o en casos donde se acepta una coincidencia parcial.
Las operaciones de unión externa se pueden dividir en tres tipos: uniones EXTERIORES IZQUIERDAS, uniones EXTERIORES DERECHAS y uniones EXTERIORES COMPLETAS. Las uniones EXTERIORES IZQUIERDAS, o simplemente uniones izquierdas, devuelven todas las filas coincidentes de las dos tablas unidas, así como todas las filas no coincidentes de la tabla "izquierda". En el contexto de una operación JOIN, la tabla "izquierda" siempre es la primera tabla especificada inmediatamente después de la palabra clave FROM y a la izquierda de la palabra clave JOIN. De manera similar, la tabla "derecha" es la segunda tabla, o la tabla que viene inmediatamente después de JOIN, y una unión EXTERIOR DERECHA devuelve todas las filas coincidentes de las tablas unidas, junto con todas las filas no coincidentes de la tabla "derecha". FULL OUTER JOIN devuelve todas las filas de ambas tablas, incluidas las filas de cualquiera de las tablas que no coinciden.
Para demostrar cómo estos diferentes tipos de cláusulas JOIN devuelven datos, ejecute las siguientes consultas de ejemplo en las tablas creadas en la sección anterior "Conexión y configuración de una base de datos de ejemplo". Estas consultas son idénticas, salvo que cada una especifica un tipo diferente de cláusula JOIN.
Este primer ejemplo utiliza una unión interna para combinar las tablas de ventas y equipo mediante la coincidencia de las columnas de vendedor y empID correspondientes. De nuevo, la palabra clave INNER está implícita, aunque no se incluya explícitamente:
SELECT sales.saleID, sales.quantity, sales.salesperson, team.empName
FROM sales JOIN team
ON sales.salesperson = team.empID;Output +--------+----------+-------------+----------+ | saleID | quantity | salesperson | empName | +--------+----------+-------------+----------+ | 1 | 7 | 1 | Florence | | 4 | 1 | 3 | Diana | | 5 | 5 | 3 | Diana | | 2 | 10 | 4 | Betty | | 3 | 8 | 4 | Betty | +--------+----------+-------------+----------+ 5 rows in set (0.00 sec)
SELECT sales.saleID, sales.quantity, sales.salesperson, team.empName
FROM sales LEFT OUTER JOIN team
ON sales.salesperson = team.empID;Output
+--------+----------+-------------+----------+
| saleID | quantity | salesperson | empName |
+--------+----------+-------------+----------+
| 1 | 7 | 1 | Florence |
| 2 | 10 | 4 | Betty |
| 3 | 8 | 4 | Betty |
| 4 | 1 | 3 | Diana |
| 5 | 5 | 3 | Diana |
| 6 | 1 | NULL | NULL |
| 7 | 3 | NULL | NULL |
| 8 | 4 | NULL | NULL |
+--------+----------+-------------+----------+
8 rows in set (0.00 sec)SELECT sales.saleID, sales.quantity, sales.salesperson, team.empName
FROM sales RIGHT JOIN team
ON sales.salesperson = team.empID;Tenga en cuenta que la cláusula JOIN de esta consulta indica "RIGHT JOIN" en lugar de "RIGHT OUTER JOIN". Así como la palabra clave INNER no es necesaria para especificar una cláusula INNER JOIN, OUTER se implica al escribir "LEFT JOIN" o "RIGHT JOIN".
El resultado de esta consulta es el opuesto al anterior, ya que devuelve todas las filas de ambas tablas, pero solo filas únicas de la tabla “correcta”:
Output
+--------+----------+-------------+----------+
| saleID | quantity | salesperson | empName |
+--------+----------+-------------+----------+
| 1 | 7 | 1 | Florence |
| NULL | NULL | NULL | Mary |
| 4 | 1 | 3 | Diana |
| 5 | 5 | 3 | Diana |
| 2 | 10 | 4 | Betty |
| 3 | 8 | 4 | Betty |
+--------+----------+-------------+----------+
6 rows in set (0.00 sec)Alias de tablas y columnas en cláusulas JOIN
Al unir tablas con nombres largos o muy descriptivos, escribir múltiples referencias de columna completas puede resultar tedioso. Para evitarlo, a veces resulta útil proporcionar un alias más corto para el nombre de la tabla o columna.
Puede hacer esto en SQL siguiendo cada definición de tabla en la cláusula FROM con la palabra clave AS y luego con el alias de su elección:
SELECT t1.column1, t2.column2
FROM table1 AS t1 JOIN table2 AS t2
ON t1.related_column = t2.related_column;Esta sintaxis de ejemplo utiliza alias en la cláusula SELECT, aunque no estén definidos antes de la cláusula FROM. Esto es posible porque, en las consultas SQL, el orden de ejecución comienza con la cláusula FROM. Esto puede resultar confuso, pero conviene recordarlo y considerar los alias antes de empezar a escribir la consulta.
Por ejemplo, ejecute la siguiente consulta que une las tablas Ventas y Productos, proporcionándoles los alias S y P, respectivamente:
SELECT S.saleID, S.quantity,
P.productName,
(P.price * S.quantity) AS revenue
FROM sales AS S JOIN products AS P
USING (productID);Output
+--------+----------+-------------+---------+
| saleID | quantity | productName | revenue |
+--------+----------+-------------+---------+
| 1 | 7 | widget | 132.93 |
| 2 | 10 | whatzit | 299.90 |
| 3 | 8 | gizmo | 115.92 |
| 4 | 1 | thingamajig | 39.99 |
| 5 | 5 | widget | 94.95 |
| 6 | 1 | whatzit | 29.99 |
| 7 | 3 | widget | 56.97 |
| 8 | 4 | whatzit | 119.96 |
+--------+----------+-------------+---------+
8 rows in set (0.00 sec)SELECT S.saleID, S.quantity, P.productName, (P.price * S.quantity) revenue
FROM sales S JOIN products P
USING (productID);Aunque la palabra clave AS no es necesaria para definir un alias, se recomienda incluirla. Esto ayuda a mantener clara la intención de la consulta y a mejorar su legibilidad.
Resultado
Al leer esta guía, aprendió a usar la operación JOIN para combinar tablas independientes en un conjunto de resultados de consulta. Si bien los comandos que se muestran aquí deberían funcionar en la mayoría de las bases de datos relacionales, tenga en cuenta que cada base de datos SQL utiliza su propia implementación del lenguaje. Consulte la documentación de su sistema de gestión de bases de datos (SGBD) para obtener una explicación más completa de cada comando y sus opciones.









