SQL izquierda unirse vs múltiples tablas en la línea de?


La mayoría de los dialectos SQL aceptan las siguientes consultas:

SELECT a.foo, b.foo
FROM a, b
WHERE a.x = b.x

SELECT a.foo, b.foo
FROM a
LEFT JOIN b ON a.x = b.x

Ahora, obviamente, cuando se necesita una unión externa, se requiere la segunda sintaxis. Pero al hacer una unión interna ¿por qué debería preferir la segunda sintaxis a la primera (o viceversa)?

Author: Kev, 2009-05-21

11 answers

La sintaxis antigua, con solo enumerar las tablas, y usar la cláusula WHERE para especificar los criterios de unión, está siendo obsoleta en la mayoría de las bases de datos modernas.

No es solo para show, la sintaxis antigua tiene la posibilidad de ser ambigua cuando se utilizan las uniones INTERNAS y EXTERNAS en la misma consulta.

Permítanme darles un ejemplo.

Supongamos que tiene 3 tablas en su sistema:

Company
Department
Employee

Cada tabla contiene numerosas filas, unidas entre sí. Tienes varias compañías, y cada empresa puede tener varios departamentos y cada departamento puede tener varios empleados.

Ok, así que ahora quieres hacer lo siguiente:

Enumerar todas las empresas, e incluir todos sus departamentos, y todos sus empleados. Tenga en cuenta que algunas empresas no tienen departamentos todavía, pero asegúrese de incluirlos también. Asegúrese de recuperar solo los departamentos que tienen empleados, pero siempre enumere todas las empresas.

Así que haces esto:

SELECT * -- for simplicity
FROM Company, Department, Employee
WHERE Company.ID *= Department.CompanyID
  AND Department.ID = Employee.DepartmentID

Nota que el último haya una unión interior, con el fin de cumplir los criterios de que solo quieres departamentos con personas.

Ok, entonces qué pasa ahora. Bueno, el problema es que depende del motor de base de datos, el optimizador de consultas, índices y estadísticas de tablas. Déjame explicarte.

Si el optimizador de consultas determina que la forma de hacer esto es primero tomar una empresa, luego encontrar los departamentos y luego hacer una unión interna con los empleados, no obtendrá ninguna empresa que no lo haga tienen departamentos.

La razón de esto es que la cláusula WHERE determina qué filas terminan en el resultado final, no partes individuales de las filas.

Y en este caso, debido a la unión izquierda, la Department.ID columna será NULO, y por lo tanto cuando se trata de la UNIÓN INTERNA a Empleado, no hay manera de cumplir con esa restricción para la fila de empleado, y por lo que no aparecerá.

Por otro lado, si el optimizador de consultas decide abordar el departamento-empleado únase primero, y luego haga una unión a la izquierda con las empresas, las verá.

Así que la sintaxis antigua es ambigua. No hay manera de especificar lo que desea, sin tratar con sugerencias de consulta, y algunas bases de datos no tienen manera en absoluto.

Ingrese la nueva sintaxis, con esto puede elegir.

Por ejemplo, si desea todas las empresas, como se indica en la descripción del problema, esto es lo que escribiría:

SELECT *
FROM Company
     LEFT JOIN (
         Department INNER JOIN Employee ON Department.ID = Employee.DepartmentID
     ) ON Company.ID = Department.CompanyID

Aquí usted especifica que desea que se realice la unión departamento-empleado como uno unirse, y luego a la izquierda unirse a los resultados de que con las empresas.

Además, digamos que solo quieres departamentos que contengan la letra X en su nombre. Una vez más, con las uniones de estilo antiguo, corre el riesgo de perder la empresa también, si no tiene ningún departamento con una X en su nombre, pero con la nueva sintaxis, puede hacer esto:

SELECT *
FROM Company
     LEFT JOIN (
         Department INNER JOIN Employee ON Department.ID = Employee.DepartmentID
     ) ON Company.ID = Department.CompanyID AND Department.Name LIKE '%X%'

Esta cláusula extra se usa para la unión, pero no es un filtro para toda la fila. Así que la fila podría aparecer con información de la empresa, pero podría tener NULOs en todas las columnas de departamento y empleado para esa fila, porque no hay ningún departamento con una X en su nombre para esa empresa. Esto es difícil con la vieja sintaxis.

Esta es la razón por la que, entre otros proveedores, Microsoft ha desaprobado la antigua sintaxis de unión externa, pero no la antigua sintaxis de unión interna, desde SQL Server 2005 y en adelante. La única manera de hablar con una base de datos que se ejecuta en Microsoft SQL Server 2005 o 2008, utilizando la sintaxis de unión externa de estilo antiguo, es establecer esa base de datos en 8.0 modo de compatibilidad (también conocido como SQL Server 2000).

Además, la forma antigua, al lanzar un montón de tablas en el optimizador de consultas, con un montón de cláusulas WHERE, era similar a decir "aquí estás, haz lo mejor que puedas". Con la nueva sintaxis, el optimizador de consultas tiene menos trabajo que hacer para averiguar qué partes van juntas.

Así que ahí lo tienen.

LA UNIÓN IZQUIERDA e INTERIOR es la ola del futuro.

 293
Author: Lasse Vågsæther Karlsen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-15 10:24:15

La sintaxis JOIN mantiene las condiciones cerca de la tabla a la que se aplican. Esto es especialmente útil cuando se une a una gran cantidad de tablas.

Por cierto, también puedes hacer una unión externa con la primera sintaxis:

WHERE a.x = b.x(+)

O

WHERE a.x *= b.x

O

WHERE a.x = b.x or a.x not in (select x from b)
 16
Author: Andomar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-21 18:56:38

La primera forma es el estándar más antiguo. El segundo método se introdujo en SQL-92, http://en.wikipedia.org/wiki/SQL . El estándar completo se puede ver en http://www.contrib.andrew.cmu.edu / ~shadow/sql/sql1992.txt .

Pasaron muchos años antes de que las compañías de bases de datos adoptaran el estándar SQL-92.

Así que la razón por la que se prefiere el segundo método, es el estándar SQL según el comité de estándares ANSI e ISO.

 10
Author: Dwight T,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-21 20:06:19

Se prefiere la segunda porque es mucho menos probable que resulte en una unión cruzada accidental olvidando poner en la cláusula where. Una combinación sin ninguna cláusula on fallará en la comprobación de sintaxis, una combinación de estilo antiguo con ninguna cláusula where no fallará, hará una combinación cruzada.

Además, cuando más tarde tenga que unirse a la izquierda, es útil para el mantenimiento que todos estén en la misma estructura. Y la sintaxis antigua ha estado desactualizada desde 1992, ya es hora de dejar de usar se.

Además, he encontrado que muchas personas que usan exclusivamente la primera sintaxis realmente no entienden las uniones y comprender las uniones es fundamental para obtener resultados correctos al realizar consultas.

 9
Author: HLGEM,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-21 19:02:38

Básicamente, cuando tu cláusula FROM enumera tablas de la siguiente manera:

SELECT * FROM
  tableA, tableB, tableC

El resultado es un producto cruzado de todas las filas en las tablas A, B, C. Luego se aplica la restricción WHERE tableA.id = tableB.a_id que tirará un gran número de filas, luego más ... AND tableB.id = tableC.b_id y entonces deberías obtener solo aquellas filas que realmente te interesen.

Los DBMSs saben cómo optimizar este SQL para que la diferencia de rendimiento para escribir esto usando JOINs sea insignificante (si la hay). El uso de la notación JOIN hace que el SQL sentencia más legible (en mi humilde opinión, no usar joins convierte la sentencia en un lío). Usando el producto cruzado, debe proporcionar criterios de unión en la cláusula WHERE, y ese es el problema con la notación. Estás llenando tu cláusula WHERE con cosas como

    tableA.id = tableB.a_id 
AND tableB.id = tableC.b_id 

Que solo se utiliza para restringir el producto cruzado. La cláusula WHERE solo debe contener RESTRICCIONES al conjunto de resultados. Si mezcla los criterios de unión de la tabla con las restricciones del conjunto de resultados, usted (y otros) encontrarán su consulta más difícil de leer. Definitivamente deberías usar JOINs y mantener la cláusula FROM a cláusula FROM, y la cláusula WHERE a cláusula WHERE.

 9
Author: Peter Perháč,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-13 10:40:05

Creo que hay algunas buenas razones en esta página para adoptar el segundo método-usando combinaciones explícitas. Sin embargo, el factor decisivo es que cuando los criterios de UNIÓN se eliminan de la cláusula WHERE, resulta mucho más fácil ver los criterios de selección restantes en la cláusula WHERE.

En declaraciones SELECT realmente complejas, se vuelve mucho más fácil para un lector comprender lo que está sucediendo.

 6
Author: Alan G,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-25 10:17:55

La sintaxis SELECT * FROM table1, table2, ... está bien para un par de tablas, pero se vuelve exponencialmente ( no necesariamente una declaración matemáticamente precisa) más y más difícil de leer a medida que aumenta el número de tablas.

La sintaxis JOIN es más difícil de escribir (al principio), pero hace explícito qué criterios afectan a qué tablas. Esto hace que sea mucho más difícil cometer un error.

También, si todas las uniones son INTERNAS, entonces ambas versiones son equivalentes. Sin embargo, el momento en que usted tiene un EXTERIOR únete en cualquier parte de la declaración, las cosas se complican mucho más y es prácticamente garantía de que lo que escribes no estará consultando lo que crees que escribiste.

 5
Author: Euro Micelli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-21 19:15:53

Cuando se necesita una unión externa la segunda sintaxis es no siempre se requiere:

Oráculo:

SELECT a.foo, b.foo
  FROM a, b
 WHERE a.x = b.x(+)

MSSQLServer (aunque ha sido obsoleto en la versión de 2000) / Sybase:

SELECT a.foo, b.foo
  FROM a, b
 WHERE a.x *= b.x

Pero volviendo a tu pregunta. No conozco la respuesta, pero probablemente está relacionada con el hecho de que un join es más natural (sintácticamente, al menos) que agregar una expresión a una cláusula where cuando estás haciendo exactamente eso: joining.

 2
Author: Pablo Santa Cruz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-21 19:33:43

He oído que mucha gente se queja de que el primero es demasiado difícil de entender y que no está claro. No veo ningún problema con eso, pero después de tener esa discusión, uso la segunda incluso en UNIONES INTERNAS para mayor claridad.

 0
Author: kemiller2002,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-21 18:55:50

Para la base de datos, terminan siendo los mismos. Para ti, sin embargo, tendrás que usar esa segunda sintaxis en algunas situaciones. Por el bien de las consultas de edición que terminan teniendo que usarlo (descubrir que necesitaba una unión izquierda donde tenía una unión recta), y para la consistencia, yo sólo patrón en el 2do método. Hará que las consultas de lectura sean más fáciles.

 0
Author: Jeff Ferland,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-21 18:56:19

Bien, la primera y la segunda consultas pueden producir resultados diferentes porque una COMBINACIÓN IZQUIERDA incluye todos los registros de la primera tabla, incluso si no hay registros correspondientes en la tabla derecha.

 0
Author: Gavin H,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-21 18:56:50