2009-08-11 20 views
5

Estoy aprendiendo SQL y estoy tratando de aprender JOINs esta semana.combinación de tres tablas con combinaciones distintas a INNER JOIN

He llegado al nivel en el que puedo hacer tres combinaciones de tablas, similar a muchos ejemplos que he visto. Todavía estoy tratando de descubrir los pequeños detalles de cómo funcionan las cosas. Todos los ejemplos que he visto de tres combinaciones de tablas usan ÚNICOS INTERNOS solamente. ¿Qué hay de IZQUIERDA y DERECHA ÚNETE? ¿Alguna vez los usaste en tres combinaciones de mesas? ¿Qué significaría?

SELECT ~some columns~ FROM ~table name~ 
LEFT JOIN ~table 2~ ON ~criteria~ 
INNER JOIN ~table 3~ ON ~criteria~ 

o

SELECT ~some columns~ FROM ~table name~ 
INNER JOIN ~table 2~ ON ~criteria~ 
LEFT JOIN ~table 3~ ON ~criteria~ 

o

SELECT ~some columns~ FROM ~table name~ 
LEFT JOIN ~table 2~ ON ~criteria~ 
LEFT JOIN ~table 3~ ON ~criteria~ 

o

???

Sólo tratando de explorar el espacio tanto como sea posible

+0

En un caso práctico, considere usar múltiples sqls para obtener las filas deseadas en lugar de hacer una combinación. muchas veces se encontraría con un mejor desempeño. esp verdadero para múltiples combinaciones de tablas en mysql. mysql fuerzas brutas para averiguar el mejor orden de unión, lo que significa que se puede gastar mucho tiempo en la optimización de consultas cuando se trata de muchas tablas. –

+0

¿cómo sería una consulta de 'múltiples SQL'? – MedicineMan

Respuesta

22

Sí, yo utilizo los tres de los JOINs, a pesar de que tienden a pegarse a usar sólo LEFT (OUTER) JOIN s en lugar de inter-mezcla LEFT and RIGHT JOINs. También uso FULL OUTER JOIN sy CROSS JOIN s.

En resumen, un INNER JOIN restringe el conjunto de resultados solo a aquellos registros satisfechos por la condición JOIN. Tenga en cuenta las siguientes tablas

EDIT: He cambiado el nombre de los nombres de tabla y el prefijo con @ de modo que las variables de tabla se pueden utilizar para cualquiera que lea esta respuesta y con ganas de experimentar.

Si también desea experimentar con esto en el navegador, I've set this all up on SQL Fiddle también;

@Table1 

id | name 
--------- 
1 | One 
2 | Two 
3 | Three 
4 | Four 

@Table2 

id | name 
--------- 
1 | Partridge 
2 | Turtle Doves 
3 | French Hens 
5 | Gold Rings 

código SQL

DECLARE @Table1 TABLE (id INT PRIMARY KEY CLUSTERED, [name] VARCHAR(25)) 

INSERT INTO @Table1 VALUES(1, 'One'); 
INSERT INTO @Table1 VALUES(2, 'Two'); 
INSERT INTO @Table1 VALUES(3, 'Three'); 
INSERT INTO @Table1 VALUES(4, 'Four'); 

DECLARE @Table2 TABLE (id INT PRIMARY KEY CLUSTERED, [name] VARCHAR(25)) 

INSERT INTO @Table2 VALUES(1, 'Partridge'); 
INSERT INTO @Table2 VALUES(2, 'Turtle Doves'); 
INSERT INTO @Table2 VALUES(3, 'French Hens'); 
INSERT INTO @Table2 VALUES(5, 'Gold Rings'); 

una sentencia SQL INNER JOIN, se unieron en el campo id

SELECT 
    t1.id, 
    t1.name, 
    t2.name 
FROM 
    @Table1 t1 
INNER JOIN 
    @Table2 t2 
    ON 
     t1.id = t2.id 

Resultados en

id | name | name 
---------------- 
1 | One | Partridge 
2 | Two | Turtle Doves 
3 | Three| French Hens 

Un LEFT JOIN devolverá un conjunto de resultados con todos los registros de la tabla en el lado izquierdo de la unión (si tuviera que escribir la declaración como un revestimiento, la tabla que aparece primero) y los campos de la tabla en el lado derecho de la join que coinciden con la expresión de unión y están incluidos en la cláusula SELECT.Missing datos se rellenarán con NULL

SELECT 
    t1.id, 
    t1.name, 
    t2.name 
FROM 
    @Table1 t1 
LEFT JOIN 
    @Table2 t2 
    ON 
     t1.id = t2.id 

Resultados en

id | name | name 
---------------- 
1 | One | Partridge 
2 | Two | Turtle Doves 
3 | Three| French Hens 
4 | Four | NULL 

Un RIGHT JOIN es la misma lógica que un LEFT JOIN y luego se volverá todos los registros desde el lado derecho de la unión y campos desde el lado izquierdo que coinciden con la expresión de unión y están incluidos en la cláusula SELECT.

SELECT 
    t1.id, 
    t1.name, 
    t2.name 
FROM 
    @Table1 t1 
RIGHT JOIN 
    @Table2 t2 
    ON 
     t1.id = t2.id 

Resultados en

id | name | name 
---------------- 
1 | One | Partridge 
2 | Two | Turtle Doves 
3 | Three| French Hens 
NULL| NULL| Gold Rings 

Por supuesto, también existe la FULL OUTER JOIN, que incluye los registros de ambas tablas de combinación y rellena cualquier falta detalles con NULL.

SELECT 
    t1.id, 
    t1.name, 
    t2.name 
FROM 
    @Table1 t1 
FULL OUTER JOIN 
    @Table2 t2 
    ON 
     t1.id = t2.id 

Resultados en

id | name | name 
---------------- 
1 | One | Partridge 
2 | Two | Turtle Doves 
3 | Three| French Hens 
4 | Four | NULL 
NULL| NULL| Gold Rings 

y una CROSS JOIN (también conocido como CARTESIAN PRODUCT), que es simplemente el producto de la cruz aplicación de campos en la instrucción SELECT de una tabla con los campos en la instrucción SELECT de la otra mesa. Observe que no hay es la expresión de combinación en un CROSS JOIN

SELECT 
    t1.id, 
    t1.name, 
    t2.name 
FROM 
    @Table1 t1 
CROSS JOIN 
    @Table2 t2 

Resultados en

id | name | name 
------------------ 
1 | One | Partridge 
2 | Two | Partridge 
3 | Three | Partridge 
4 | Four | Partridge 
1 | One | Turtle Doves 
2 | Two | Turtle Doves 
3 | Three | Turtle Doves 
4 | Four | Turtle Doves 
1 | One | French Hens 
2 | Two | French Hens 
3 | Three | French Hens 
4 | Four | French Hens 
1 | One | Gold Rings 
2 | Two | Gold Rings 
3 | Three | Gold Rings 
4 | Four | Gold Rings 

EDIT:

imaginar que haya ahora un Tabla3

@Table3 

id | name 
--------- 
2 | Prime 1 
3 | Prime 2 
5 | Prime 3 

El código SQL

DECLARE @Table3 TABLE (id INT PRIMARY KEY CLUSTERED, [name] VARCHAR(25)) 

INSERT INTO @Table3 VALUES(2, 'Prime 1'); 
INSERT INTO @Table3 VALUES(3, 'Prime 2'); 
INSERT INTO @Table3 VALUES(5, 'Prime 3'); 

Ahora las tres tablas unidas con INNER JOINS

SELECT 
    t1.id, 
    t1.name, 
    t2.name, 
    t3.name 
FROM 
    @Table1 t1 
INNER JOIN 
    @Table2 t2 
    ON 
     t1.id = t2.id 
INNER JOIN 
    @Table3 t3 
    ON 
     t1.id = t3.id 

Resultados en

id | name | name   | name 
------------------------------- 
2 | Two | Turtle Doves | Prime 1 
3 | Three| French Hens | Prime 2 

Podría ayudar a entender este resultado por el pensamiento de que los registros con el ID 2 y 3 son los únicos comunes a las 3 tablas y son también el campo en el que nos estamos uniendo en cada tabla.

Ahora los tres con LEFT JOINS

SELECT 
    t1.id, 
    t1.name, 
    t2.name, 
    t3.name 
FROM 
    @Table1 t1 
LEFT JOIN 
    @Table2 t2 
    ON 
     t1.id = t2.id 
LEFT JOIN 
    @Table3 t3 
    ON 
     t1.id = t3.id 

Resultados en

id | name | name   | name 
------------------------------- 
1 | One | Partridge | NULL 
2 | Two | Turtle Doves | Prime 1 
3 | Three| French Hens | Prime 2 
4 | Four | NULL   | NULL 

Joel's answer es una buena explicación para explicar este conjunto de resultados (Tabla 1 es la tabla base/origen).

Ahora con un INNER JOIN y una LEFT JOIN

SELECT 
    t1.id, 
    t1.name, 
    t2.name, 
    t3.name 
FROM 
    @Table1 t1 
INNER JOIN 
    @Table2 t2 
    ON 
     t1.id = t2.id 
LEFT JOIN 
    @Table3 t3 
    ON 
     t1.id = t3.id 

Resultados en

id | name | name   | name 
------------------------------- 
1 | One | Partridge | NULL 
2 | Two | Turtle Doves | Prime 1 
3 | Three| French Hens | Prime 2 

Aunque no conocemos el orden en que el optimizador de consultas llevará a cabo las operaciones, vamos a ver en esta consulta de arriba a abajo para comprender el conjunto de resultados. El INNER JOIN en los identificadores entre Table1 y Table2 restringirá el conjunto de resultados a solo aquellos registros que satisfagan la condición de unión, es decir, las tres filas que vimos en el primer ejemplo. Este temporal resultados será LEFT JOIN ed a la Tabla 3 en los identificadores entre Table1 y Tablas; Hay registros en la Tabla 3 con id 2 y 3, pero no id 1, por lo que el campo t3.name tendrá detalles para 2 y 3, pero no 1.

+0

Aunque hace mucho tiempo, me gusta esta respuesta debido al detalle que entró Russ para explicar que la tabla se une: muy poco contenido abstracto aquí, todas las tablas con su los datos, la consulta y el resultado están detallados. – MedicineMan

+0

También me gusta la progresión de la respuesta: tomar el caso INNER e INNER, y luego mostrar las permutaciones y los resultados. Ayuda que su conjunto de datos se haya diseñado de una manera que ilustre claramente las diferencias entre las consultas. – MedicineMan

+0

Gracias: he agregado detalles adicionales para permitir que otros ejecuten las instrucciones en SQL Server y puedan ver los resultados, así como también experimentar. –

0

Esto realmente depende de lo que está haciendo. He escrito más de 3 consultas de tabla que tendrán una combinación externa en ellas. Solo depende de los datos que está consultando y de lo que intenta seguir.

La misma lógica general se aplica al seleccionar el tipo de combinación cuando tiene múltiples como con las consultas de unión única.

6

Las uniones son solo formas de combinar tablas. Unirse a tres tablas no es diferente de unir 2 ... o 200. Puede mezclar y combinar INNER, [LEFT/RIGHT/FULL] OUTER, e incluso CROSS se une tanto como desee. La única diferencia es qué resultados se guardan: las combinaciones INNER solo conservan las filas donde ambos lados coinciden con la expresión. OUTER joins selecciona una tabla de "origen" dependiendo de la especificación IZQUIERDA/DERECHA/LLENA, siempre conserva todas las filas de la tabla de origen y proporciona valores NULOS para las filas del otro lado que no coinciden con la expresión. Las combinaciones CROSS devuelven todas las combinaciones posibles de ambos lados.

El truco es que, debido a que está trabajando con código declarativo en lugar de iterativo más familiar, la tentación es tratar de pensarlo como si todo sucediera a la vez. Cuando haces eso, tratas de entender la consulta completa y puede ser confuso.

En su lugar, debe considerarlo como si las uniones ocurrieran en orden, desde la primera tabla enumerada hasta la última. De hecho, no es así como funciona, porque el optimizador de consultas puede reorganizar las cosas para que se ejecuten más rápido. Pero hace que la construcción de la consulta sea más fácil para el desarrollador.

Así, con tres tablas, se empieza con su tabla de base, a continuación, se unen en los valores que necesita de la siguiente tabla, y el siguiente, y así sucesivamente, al igual que la adición de líneas de código para una función para producir la salida requerida .

En cuanto a la utilización de los diferentes tipos de unión, he usado todos los tipos que he enumerado aquí: INTERIOR, IZQUIERDA EXTERIOR, DERECHA EXTERIOR, EXTERIOR COMPLETA y CRUZADA. Pero la mayoría de esos solo debes usar ocasionalmente. INNER JOIN y LEFT JOIN cubrirán probablemente el 95% o más de lo que desea hacer.

Ahora hablemos del rendimiento. A menudo, el orden en que se enumeran las tablas se dicta a usted: se inicia desde TableA y necesita enumerar TableB primero para tener acceso a las columnas necesarias para unirse al TableC. Pero a veces tanto TableB como TableC solo dependen de TableA, y puede enumerarlos en cualquier orden.Cuando eso suceda, el optimizador de consultas generalmente seleccionará el mejor orden para usted, pero a veces no sabe cómo hacerlo. Incluso si lo hiciera, es útil contar con un buen sistema para listar tablas, de modo que siempre pueda ver una consulta y saber que es "correcta".

Teniendo esto en cuenta, debe pensar en una consulta en términos de working set actualmente en memoria a medida que se crea la consulta. Cuando comienza con TableA, la base de datos examina todas las columnas de TableA en la lista de selección o en cualquier otro lugar (como cláusulas WHERE u ORDER BY, o índices potenciales) en la consulta, factores en condiciones relevantes de la cláusula WHERE y carga el porción más pequeña de esa tabla en la memoria que puede salirse con la suya. Lo hace para cada tabla, siempre cargando lo menos posible. Y esa es la clave: desea mantener este conjunto de trabajo lo más pequeño posible durante el mayor tiempo posible.

Por lo tanto, volviendo a nuestra unión de tres tablas, queremos enumerar las tablas en el orden que mantendrá el conjunto de trabajo más pequeño durante más tiempo. Esto significa enumerar la tabla más pequeña encima de la más grande. Otra buena regla general es que las uniones INNER tienden a contraer conjuntos de resultados, mientras que OUTER se une, tienden a crecer conjuntos de resultados, por lo que desea enumerar primero sus uniones INNER. Sin embargo, esto no es un requisito para que una consulta funcione, ni siempre es cierto; a veces lo contrario también puede ocurrir.

Finalmente, quiero señalar una vez más que esto no es así como realmente funciona. El optimizador de consultas y los planes de ejecución son un tema muy complejo, y existen muchos trucos que la base de datos puede realizar para romper este modelo de vez en cuando. Es solo un modelo que usted, como desarrollador, puede usar para comprender lo que hace el servidor y ayudarlo a escribir mejores consultas.

+0

esta es una respuesta realmente excelente. Sus comentarios sobre el rendimiento (párrafos 7 y 8) son muy esclarecedores. ¿Hay algún artículo o tema que pueda leer para conocer más sobre esto? Me gustaría entender tus puntos con más detalles. – MedicineMan

+0

Esto es lo que he derivado de la experiencia personal, principalmente a través de un buen mentor en un empleador anterior. Sin embargo, esto se trata principalmente de formatear; el rendimiento obtenido de este modelo es mínimo, y el optimizador de consultas suele ser más inteligente de lo que usted es. Lo uso porque me permite identificar cuándo mi idea sobre qué tablas son los cambios más importantes o cuándo cometí un error al crear una consulta. Podré detectar uniones fuera de servicio. –

2

Seleccionar de tres tablas no es diferente de seleccionar solo dos (o tanto como cien, aunque sería una consulta bastante fea para leer).

Para CADA unión que se escriba, tener INNER indica que solo quiere filas que unen exitosamente esas dos tablas. Si otras tablas se unieron anteriormente en la consulta, esos resultados ahora son completamente irrelevantes, excepto en la medida en que sus propias condiciones de suscripción los invoquen.

Por ejemplo:

SELECT person.* 
FROM person 
LEFT JOIN vehicle ON (person.person_id = vehicle.owner_id) 
LEFT JOIN house ON (person.person_id = house.owner_id) 

aquí quiero una lista de todas las personas, y (si está disponible) todos los vehículos y las casas de su propiedad.

alternativa:

SELECT person.* 
FROM person 
INNER JOIN vehicle ON (person.person_id = vehicle.owner_id) 
LEFT JOIN house ON (person.person_id = house.owner_id) 

aquí quiero todas las personas que son dueños de los vehículos (que imprescindible poseer un vehículo para obtener resultados en mi consulta), y (si está disponible) todas las casas de su propiedad).

Cada unión está completamente separada aquí.

Por supuesto, variando lo que pone en la cláusula ON, puede hacer uniones de tablas interrelacionadas de la forma que desee.

0

Por el bien de este ejemplo, digamos que tenemos una tabla "empleados" con un ID, NOMBRE y campos MANAGER_ID.

Aquí es una simple consulta:

SELECT E.ID, E.NAME, M.NAME AS MANAGER 
FROM EMPLOYEES E 
JOIN EMPLOYEE M ON E.MANAGER_ID = M.ID 

Esto devolverá todos los empleados, con su nombre del gestor. ¿Pero qué pasa para el jefe? el que no tiene gerente? Un nulo en la base de datos realmente evitaría que esa fila vuelva, ya que no podría encontrar un registro coincidente para unirse. Por lo tanto, usaría una combinación EXTERIOR (izquierda o derecha dependiendo de cómo escriba la consulta).

La misma lógica sería válida para escribir una consulta con 2 + n combinaciones. Si posiblemente va a tener filas que no tienen coincidencias en su cláusula join, y quiere que esas filas vuelvan (aunque con valores nulos), entonces está dorado.

0

En algunos motores SQL hay un problema en el que se está uniendo a Utilizando combinación izquierda. Si se une a A-> B-> C y la fila en B no existe, entonces la columna de unión de B es NULA. Algunos que he usado requieren que la combinación de B-> C sea una combinación de la izquierda si la combinación de A-> B es una combinación de la izquierda.

Esto está bien

select a.*, b.*, c.* 
from a 
left join b on b.id = a.id 
left join c on c.id = b.id 

esto no es

select a.*, b.*, c.* 
from a 
left join b on b.id = a.id 
inner join c on c.id = b.id 
+0

Esta pregunta está limitada a SQL Server 2000, 2005 y 2008 – MedicineMan

0

Por razones de completitud y evangelios estándar, sonaré con la sintaxis de ANSI 92 anidado:

select t1.* 
    ,t2.* 
    ,t3.* 
from table1 t1 
    left outer join (
     table2 t2 left outer join table3 t3 on (t2.b = t3.b) 
    ) on (t1.a = t2.a) 

Su motor SQL de elección puede optimizar para ellos.

+0

+1 si puede indicar qué es diferente acerca de su sintaxis de lo que se ha escrito hasta ahora ... ¿Existe algún requisito de ANSI 92 que sea diferente al anterior? ¿Qué estándar usa el anterior? No estoy familiarizado con ANSI 92. Finalmente, ¿por qué alguien querría usar ANSI 92 en lugar de lo anterior? – MedicineMan

+0

Es principalmente una cuestión de preferencia. Para legibilidad y con qué te sientes más cómodo. Dependiendo de la complejidad de su consulta, algunos motores SQL pueden optimizar según el orden de las operaciones, el nivel de jerarquía, etc. Al final, es lo que dice el optimizador de consultas, independientemente de la sintaxis. Información adicional: http://stackoverflow.com/questions/1094585/sql-difference-between-these-joins – maero