Consultas SQL de Unión Internas

Detallamos estas consultas del lenguaje SQL tan importantes para el buen desarrollo de una base de datos.
Consultas de Combinación entre tablas Las vinculaciones entre tablas se realizan mediante la cláusula INNER que combina registros de dos tablas siempre que haya concordancia de valores en un campo común. Su sintaxis es:

SELECT campos FROM tb1 INNER JOIN tb2 ON
tb1.campo1 comp tb2.campo2

En donde:

tb1, tb2Son los nombres de las tablas desde las que se combinan los registros.
campo1, campo2Son los nombres de los campos que se combinan. Si no son numéricos, los campos deben ser del mismo tipo de datos y contener el mismo tipo de datos, pero no tienen que tener el mismo nombre.
compEs cualquier operador de comparación relacional: =, <,<>, <=, =>, ó >.

Se puede utilizar una operación INNER JOIN en cualquier cláusula FROM. Esto crea una combinación por equivalencia, conocida también como unión interna. Las combinaciones equivalentes son las más comunes; éstas combinan los registros de dos tablas siempre que haya concordancia de valores en un campo común a ambas tablas. Se puede utilizar INNER JOIN con las tablas Departamentos y Empleados para seleccionar todos los empleados de cada departamento. Por el contrario, para seleccionar todos los departamentos (incluso si alguno de ellos no tiene ningún empleado asignado) se emplea LEFT JOIN o todos los empleados (incluso si alguno no está asignado a ningún departamento), en este caso RIGHT JOIN.

Si se intenta combinar campos que contengan datos Memo u Objeto OLE, se produce un error. Se pueden combinar dos campos numéricos cualesquiera, incluso si son de diferente tipo de datos. Por ejemplo, puede combinar un campo Numérico para el que la propiedad Size de su objeto Field está establecida como Entero, y un campo Contador.

El ejemplo siguiente muestra cómo podría combinar las tablas Categorías y Productos basándose en el campo IDCategoria:

SELECT
    NombreCategoria, NombreProducto
FROM
   Categorias
INNER JOIN
   Productos
ON
    Categorias.IDCategoria = Productos.IDCategoria

En el ejemplo anterior, IDCategoria es el campo combinado, pero no está incluido en la salida de la consulta ya que no está incluido en la instrucción SELECT. Para incluir el campo combinado, incluir el nombre del campo en la instrucción SELECT, en este caso, Categorias.IDCategoria.

También se pueden enlazar varias cláusulas ON en una instrucción JOIN, utilizando la sintaxis siguiente:

SELECT campos FROM tabla1 INNER JOIN tabla2
ON (tb1.campo1 comp tb2.campo1 AND ON tb1.campo2 comp tb2.campo2)
OR ON (tb1.campo3 comp tb2.campo3)

También puede anidar instrucciones JOIN utilizando la siguiente sintaxis:

SELECT campos FROM tb1 INNER JOIN (tb2 INNER JOIN [( ]tb3
[INNER JOIN [( ]tablax [INNER JOIN ...)]
ON tb3.campo3 comp tbx.campox)]
ON tb2.campo2 comp tb3.campo3)
ON tb1.campo1 comp tb2.campo2

Un LEFT JOIN o un RIGHT JOIN puede anidarse dentro de un INNER JOIN, pero un INNER JOIN no puede anidarse dentro de un LEFT JOIN o un RIGHT JOIN.

Ejemplo:

SELECT DISTINCT
   Sum(PrecioUnitario * Cantidad) AS Sales,
(Nombre + ' ' + Apellido) AS Name
FROM
    Empleados
INNER JOIN(
    Pedidos
INNER JOIN
   DetallesPedidos
   ON
   Pedidos.IdPedido = DetallesPedidos.IdPedido)
    ON
    Empleados.IdEmpleado = Pedidos.IdEmpleado
GROUP BY
   Nombre + ' ' + Apellido

(Crea dos combinaciones equivalentes: una entre las tablas Detalles de pedidos y Pedidos, y la otra entre las tablas Pedidos y Empleados. Esto es necesario ya que la tabla Empleados no contiene datos de ventas y la tabla Detalles de pedidos no contiene datos de los empleados. La consulta produce una lista de empleados y sus ventas totales.)

Si empleamos la cláusula INNER en la consulta se seleccionarán sólo aquellos registros de la tabla de la que hayamos escrito a la izquierda de INNER JOIN que contengan al menos un registro de la tabla que hayamos escrito a la derecha. Para solucionar esto tenemos dos cláusulas que sustituyen a la palabra clave INNER, estas cláusulas son LEFT y RIGHT. LEFT toma todos los registros de la tabla de la izquierda aunque no tengan ningún registro en la tabla de la izquierda. RIGHT realiza la misma operación pero al contrario, toma todos los registros de la tabla de la derecha aunque no tenga ningún registro en la tabla de la izquierda.

La sintaxis expuesta anteriormente pertenece a ACCESS, en donde todas las sentencias con la sintaxis funcionan correctamente. Los manuales de SQL-SERVER dicen que esta sintaxis es incorrecta y que hay que añadir la palabra reservada OUTER: LEFT OUTER JOIN y RIGHT OUTER JOIN. En la práctica funciona correctamente de una u otra forma.

No obstante, los INNER JOIN ORACLE no es capaz de interpretarlos, pero existe una sintaxis en formato ANSI para los INNER JOIN que funcionan en todos los sistemas. Tomando como referencia la siguiente sentencia:

SELECT
   Facturas.*,
   Albaranes.*
FROM
   Facturas
INNER JOIN
   Albaranes
ON
   Facturas.IdAlbaran = Albaranes.IdAlbaran
WHERE
   Facturas.IdCliente = 325

La transformación de esta sentencia a formato ANSI sería la siguiente:

SELECT
Facturas.*,
Albaranes.*
FROM
Facturas, Albaranes
WHERE
Facturas.IdAlbaran = Albaranes.IdAlbaran
AND
Facturas.IdCliente = 325

Como se puede observar los cambios realizados han sido los siguientes:

  1. Todas las tablas que intervienen en la consulta se especifican en la cláusula FROM.
  2. Las condiciones que vinculan a las tablas se especifican en la cláusula WHERE y se vinculan mediante el operador lógico AND.
Referente a los OUTER JOIN, no funcionan en ORACLE y además conozco una sintaxis que funcione en los tres sistemas. La sintaxis en ORACLE es igual a la sentencia anterior pero añadiendo los caracteres (+) detrás del nombre de la tabla en la que deseamos aceptar valores nulos, esto equivale a un LEFT JOIN:

SELECT
   Facturas.*,
    Albaranes.*
FROM
   Facturas, Albaranes
WHERE
   Facturas.IdAlbaran = Albaranes.IdAlbaran (+)
   AND
   Facturas.IdCliente = 325

Y esto a un RIGHT JOIN:

SELECT
   Facturas.*,
    Albaranes.*
FROM
   Facturas, Albaranes
WHERE
   Facturas.IdAlbaran (+) = Albaranes.IdAlbaran
   AND
   Facturas.IdCliente = 325

En SQL-SERVER se puede utilizar una sintaxis parecida, en este caso no se utiliza los caracteres (+) sino los caracteres =* para el LEFT JOIN y *= para el RIGHT JOIN.

Consultas de Autocombinación

La autocombinación se utiliza para unir una tabla consigo misma, comparando valores de dos columnas con el mismo tipo de datos. La sintaxis en la siguiente:

SELECT
   alias1.columna, alias2.columna, ...
FROM
   tabla1 as alias1, tabla2 as alias2
WHERE
   alias1.columna = alias2.columna
AND
   otras condiciones

Por ejemplo, para visualizar el número, nombre y puesto de cada empleado, junto con el número, nombre y puesto del supervisor de cada uno de ellos se utilizaría la siguiente sentencia:

SELECT
   t.num_emp, t.nombre, t.puesto, t.num_sup,s.nombre, s.puesto
FROM
    empleados AS t, empleados AS s
WHERE
   t.num_sup = s.num_emp

Consultas de Combinaciones no Comunes

La mayoría de las combinaciones están basadas en la igualdad de valores de las columnas que son el criterio de la combinación. Las no comunes se basan en otros operadores de combinación, tales como NOT, BETWEEN, <>, etc.

Por ejemplo, para listar el grado salarial, nombre, salario y puesto de cada empleado ordenando el resultado por grado y salario habría que ejecutar la siguiente sentencia:

SELECT
   grados.grado,empleados.nombre, empleados.salario, empleados.puesto
FROM
    empleados, grados
WHERE
   empleados.salario BETWEEN grados.salarioinferior And grados.salariosuperior
ORDER BY
   grados.grado, empleados.salario

Para listar el salario medio dentro de cada grado salarial habría que lanzar esta otra sentencia:

SELECT
   grados.grado, AVG(empleados.salario)
FROM
   empleados, grados
WHERE
   empleados.salario BETWEEN grados.salarioinferior And grados.salariosuperior
GROUP BY
   grados.grado

CROSS JOIN (SQL-SERVER)

Se utiliza en SQL-SERVER para realizar consultas de unión. Supongamos que tenemos una tabla con todos los autores y otra con todos los libros. Si deseáramos obtener un listado combinar ambas tablas de tal forma que cada autor apareciera junto a cada título, utilizaríamos la siguiente sintaxis:

SELECT
    Autores.Nombre, Libros.Titulo
FROM
    Autores CROSS JOIN Libros

SELF JOIN

SELF JOIN es una técnica empleada para conseguir el producto cartesiano de una tabla consigo misma. Su utilización no es muy frecuente, pero pongamos algún ejemplo de su utilización.
Supongamos la siguiente tabla (El campo autor es numérico, aunque para ilustrar el ejemplo utilice el nombre):

Autores
Código (Código del libro)Autor (Nombre del Autor)
B00121. Francisco López
B00122. Javier Alonso
B00123. Marta Rebolledo
C00141. Francisco López
C00142. Javier Alonso
D01202. Javier Alonso
D01203. Marta Rebolledo

Queremos obtener, para cada libro, parejas de autores:

SELECT
    A.Codigo, A.Autor, B.Autor
FROM
   Autores A, Autores B
WHERE
   A.Codigo = B.Codigo

El resultado es el siguiente:

CódigoAutorAutor
B00121. Francisco López1. Francisco López
B00121. Francisco López2. Javier Alonso
B00121. Francisco López3. Marta Rebolledo
B00122. Javier Alonso 2. Javier Alonso
B00122. Javier Alonso 1. Francisco López
B00122. Javier Alonso 3. Marta Rebolledo
B0012 3. Marta Rebolledo 3. Marta Rebolledo
B00123. Marta Rebolledo 2. Javier Alonso
B00123. Marta Rebolledo 1. Francisco López
C0014 1. Francisco López1. Francisco López
C00141. Francisco López 2. Javier Alonso
C0014 2. Javier Alonso2. Javier Alonso
C0014 2. Javier Alonso1. Francisco López
D01202. Javier Alonso 2. Javier Alonso
D01202. Javier Alonso 3. Marta Rebolledo
D01203. Marta Rebolledo 3. Marta Rebolledo
D01203. Marta Rebolledo 2. Javier Alonso

Como podemos observar, las parejas de autores se repiten en cada uno de los libros, podemos omitir estas repeticiones de la siguiente forma

SELECT
   A.Codigo, A.Autor, B.Autor
FROM
   Autores A, Autores B
WHERE
   A.Codigo = B.Codigo AND A.Autor < B.Autor

El resultado ahora es el siguiente:

CódigoAutorAutor
B00121. Francisco López 2. Javier Alonso
B00121. Francisco López 3. Marta Rebolledo
C0014 1. Francisco López2. Javier Alonso
D01202. Javier Alonso 3. Marta Rebolledo

Ahora tenemos un conjunto de resultados en formato Autor - CoAutor.

Si en la tabla de empleados quisiéramos extraer todas las posibles parejas que podemos realizar, utilizaríamos la siguiente sentencia:

SELECT
    Hombres.Nombre, Mujeres.Nombre
FROM
   Empleados Hombre, Empleados Mujeres
WHERE
   Hombre.Sexo = 'Hombre' AND
   Mujeres.Sexo = 'Mujer' AND
    Hombres.Id <>Mujeres.Id

Para concluir supongamos la tabla siguiente:

Empleados
IdNombre SuJefe
1Marcos 6
2Lucas1
3Ana 2
4Eva 1
5Juan 6
6Antonio

Queremos obtener un conjunto de resultados con el nombre del empleado y el nombre de su jefe:

SELECT
    Emple.Nombre, Jefes.Nombre
FROM
   Empleados Emple, Empleados Jefe
WHERE
   Emple.SuJefe = Jefes.Id

Autor

Claudio

Compartir

Comentarios

Vlad

18/2/2006
hola, el articulo es bueno, solo me gustaria aclarar que en el caso de que el WHERE lleve filtros (p.e. Facturas.IdCliente = 325), es mejor ponerlos antes de los JOINS para que el tiempo que tarda en pasar por las filas de las tablas involucradas sea menor :)

asi tambien, en el caso de los empleados y "SuJefe", si tuvieramos restricciones de "not null" o de llaves foraneas, no se podria poner al empleado numero 1 (Marcos) con SuJefe 6 porque el empleado numero 6 aun no existe.

saludos.

ixtarix

05/2/2007
gracias por el artículo.
Creo que hay una errata en el párrafo:
" LEFT toma todos los registros de la tabla de la izquierda aunque no tengan ningún registro en la tabla de la izquierda. " (debía ser derecha, supongo)

saludos

JAhlli

11/9/2007
He encontrado un error en el articulo sobre la respresentacion simbolica( =* , *= ) tanto del left join como del right join en ms sql server ya que no es asi como en realidad se ejecuta sino al reves osea el *= es para left join y el =* es para el right.

eso seria todo ...

Jonhatan

09/4/2009
Consultas
Pero con 4 campos de dos tablas de consulta......................????????????????????????????? como sería

adrian

28/4/2009
Duda
en una base de datos tengo una tabla de alumnos con un campo clave y tengo otra tabla de calificaciones con un campo clave que permite la relacion con el alumno........ como debo de escribir mi consulta para que me muestre que alumnos ahun no tienen calificacion

MarioBurga

11/1/2010
Buen articulo
Hola, buen articulo, me sirvio para poder dar una repasada a lo que tenia en la univ.

mane

11/1/2010
Pregunta!
Quería saber si los inner Join dejan las tablas relacionadas permanentemente, o si establecen una relación solo para cuando se ejecuta la consulta.
Muchas gracias

DevCH

14/1/2010
buen articulo
Es buen artículo, pero lo que te comentan los compañeros que me antecedieron es la verdad, además aquí en desarrolloweb tienden mucho a cometer errores y solo escriben por escribir. Me ha pasado con los post de php por ejemplo...

Revisen lo que escriben antes de publicarlo.

Diego

13/3/2010
Muchas incorrecciones
La sintaxis ANSI correcta es la de los LEFT JOIN, RIGHT JOIN, INNER JOIN, no la que usa FROM tabla1, tabla2, que es obsoleta y no se recomienda. No sé de dónde sacas que no funciona en Oracle; igual es que no usaste la palabra clave OUTER, algunas bases de datos lo consideran obligatorio (esto es, sería LEFT OUTER JOIN, por ejemplo). El CROSS JOIN es el producto cartesiano; en el caso de los autores y libros te formará TODAS las parejas autor-libro posibles.

Elis

26/3/2010
Info
Si, me confundio un poco los dos ultimos errores que comentan...pero ya todo aclarado, el resto es muy buena informacion.

Gracias.

DeCasasyAUtos.com

05/6/2010
MySQL en http://www.decasasyautos.com
En <a href="http://www.decasasyautos.com">www.decasasyautos.com</a> utilizamos <a href="http://www.decasasyautos.com/busqueda_run.php?categoria=0&pais=1&kw=mysql&x=0&y=0">MySQL</a> para todas las comunicaciones.
En la <a href="http://www.decasasyautos.com">HOME</a> de <a href="http://www.decasasyautos.com">http://www.decasasyautos.com</a> en el borde inferior se encuentra el logo de <a href="http://www.decasasyautos.com/busqueda_run.php?categoria=0&pais=1&kw=mysql&x=0&y=0">MySQL</a>.
Javier.
<a href="http://www.decasasyautos.com">http://www.decasasyautos.com</a>

patonsky1

05/6/2010
lol
Este tutorial lo tengo palabra por palabra en un cuaderno de SQL que me dieron en una academia de Zaragoza, y no aparece ninguna referencia.

Calcado, HOYGAN :-/

Fer

16/9/2010
Felicitaciones
Quiero agradecerles por aportar este tutorial. Yo he aprendido desde cero php gracias a éste sitio Web principalmente y sus tutoriales, idem con las nociones de MySQL y algo de base de datos. Esto me ayuda muchísimo a aclarar el tema de los Join. Muchas gracias a todos Uds.
Fer

Cristina

05/10/2010
SELF JOIN
Me ha sido extremadamente útil el ejemplo del SELF JOIN con autores y co-autores.
Tengo una duda, pero.
He hecho algo similar con una tabla que tengo:

Documento Codigo Valor
1 A 001
1 B 002
2 A 765
2 B 456
3 A 167

Los documentos 1 y 2 tienen un registro A y B, pero el documento 3 sólo tiene registro A. Me gustaría obtener una tabla así:

Documento A B
1 001 002
2 765 456
3 167 Null

Sin embargo, sólo obtengo los dos primeros registros, el tercero no lo obtengo porque no hay registro para uno de los códigos.

La consulta que ejecuto es la siguiente:
SELECT T1.Documento, T1.Valor as A, T2.Valor as B
FROM tabla as T1, tabla as T2
WHERE T1.Codigo = A AND
T2.Codigo = B AND
T1.Documento = T2.Documento

Cómo debería hacer la consulta para obtener el resultado esperado?

Mar

12/10/2010
Gracias
Está muy bien, me ha sido de gran ayuda.
Gracias.

rookielector

31/5/2011
Excelente
Excelente articulo

Brenda

20/6/2011
ME SIRVIO DE AYUDA
Buen artículo y sencillo de entender

Débora

03/11/2011
Aclaración
Hola! Muy buen artículo y explicación.
Una observación: no sé de cuándo es la publicación pero actualmente Oracle sí trabaja con INNER, LEFT y RIGHT JOIN.
Saludos y gracias!

Valentin Zarate Gutierrez

11/11/2011
Pregunta acerca de una consulta
Hola amigos de esta pagina, tengo un problema con la siguiente consulta:
SELECT cobranza.cliente, clients.nombre, SUM( cobranza.saldo * cobranza.tip_cam ) AS 'Saldo',clients.telefono FROM cobranza INNER JOIN clients ON clients.cliente = cobranza.cliente WHERE cobranza.cobranza > 0 GROUP BY cobranza.cliente, clients.nombre ORDER BY cobranza.cliente
Al momento de hacer esta sentencia me manda este error: "Descripción: La columna 'clients.TELEFONO' de la lista de selección no es válida, porque no está contenida en una función de agregado ni en la cláusula GROUP BY."
La idea es tener obtener el nuemor de telefono de las personas que tienen saldo mayor a cero, alquien me puede ayudar, de antemano mucas gracias.

Daniel

13/11/2011
Joins en misma tabla con filas complementarias (por valores Null)
Yo tengo una duda a la hora de plantear Joins. Como lo puedo hacer en una misma tabla con filas complementarias? Pongo un ejemplo:
ID, A, B, C
123, 48, 15, Null
123, Null, Null, 12
245, 12,10, Null
345, 55, 15, Null
245, Null, Null, 10

Y lo q pretendo es q me "fusione" las filas con el mismo ID complementando la columna q es Null con la q si q está llena. Siendo el resultado:
123, 48, 15, 12
245, 12, 10, 10
345, 55, 15, Null

Gracias!

verenice

30/11/2014
consultas con inner join
como hacer una consulta de un atabla que va relacionada con 5 pero una que es ubicacion esta relacionada con vieubicacion para que me traiga el nombre de la ciudad mejor dicho ahi te dejo la consulta vale te agradeceria que me ayudaras
select usu.cedula,concat(usu.primer_nombre,usu.segundo_nombre) as nombres ,concat(usu.primer_apellido,usu.segundo_apellido) as apellidos ,concat(vl1.nombre_valor) as gen ,usu.telefono,usu.e_mail , pf.nombre_perfil , vl.nombre_valor, concat(ubi.id_ubicacion,ubi.nombre_ubica) AS ubica, concat(v.nombre_ubica) AS ubidep from tbl_usuario as usu inner join tbl_ubicacion as ubi on usu.ubicacion_id=ubi.id_ubicacion inner join tbl_perfil as pf on usu.perfil_id=pf.id_perfil inner join tbl_valor as vl on usu.area_empresa=vl.id_valor and vl.id_valor=area_empresa inner join tbl_valor as vl1 on usu.genero=vl1.id_valor and vl1.id_valor=genero INNER JOIN vieubicacion as v ON ubi.depende_ubica=v.id_ubicacion and ubi.depende_ubica order by v.nombre_ubica, ubi.nombre_ubica"

zergpc

13/12/2014
consultas
en access
quiero que en la consulta de 2 tablas me arroje los dos primeros registros de cada campo buscado como se muestra en archivo excel en hoja uno esta tabla 1 y hoja 2 esta la tabla 2 y en la hoja 3 esta la consulta que me arroja despues de hacer la consulta de los valores que tengo de la consulta solo quiero que se muestre lo del color amarillo debido a que los otros son de otros registros que no coincidieron en la consulta esto es en access.
mi duda es como arrojar solo esos datos en color amarillo
no me funciono el "top" podria ser el row pero como seria? o que puedo aplicar en access en sql
archivo excel http://1drv.ms/1sqdqBt
Saludos!!!

Pili

21/1/2015
SINTAXIS CONDICION SQL
¿Como seria la sintaxis en sql, de la condicion fecha entre parametros?
Por ejemplo que la fecha del pedido este entre una fecha inicial y una fecha final?

Ramon

26/3/2015
Entre fechas
Hola Pili.
Yo lo que haria es utilizar un BETWEEN para definir el intervalo entre dos fechas.
Por ejemplo, para una fecha date entre dos valores date1 y date2:
WHEN date BETWEEN date1 AND date2

Abigail

25/11/2016
Dos FK de la misma tabla
Hola, tengo algo asi:
CREATE TABLE base(
id_base int(3) AUTO_INCREMENT NOT NULL,
nombre_base varchar(20),
PRIMARY KEY (id_base)
)ENGINE=innodb;

CREATE TABLE vuelo(
id_vuelo int(3) AUTO_INCREMENT NOT NULL,
origen int(3),
destino int(3),
PRIMARY KEY (id_vuelo),
FOREIGN KEY (origen) REFERENCES base(id_base),
FOREIGN KEY (destino) REFERENCES base(id_base),
)ENGINE=innodb;
Al hacer la consulta de la tabla VUELO, obtengo esto:
select id_vuelo, origen,destino from vuelo;
+----------+--------+---------+
| id_vuelo | origen | destino |
+----------+--------+---------+
| 1 | 1 | 2 |
| 2 | 1 | 3 |
Mi problema es que quiero recuperar los nombres de las bases origen y destino