¿Unión izquierda de SQL frente a varias tablas en la línea FROM?

Resuelto jmucchiello asked hace 15 años • 12 respuestas

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 necesita una combinación externa, se requiere la segunda sintaxis. Pero al realizar una unión interna, ¿por qué debería preferir la segunda sintaxis a la primera (o viceversa)?

jmucchiello avatar May 22 '09 01:05 jmucchiello
Aceptado

La sintaxis antigua, que consistía simplemente en enumerar las tablas y utilizar la WHEREcláusula para especificar los criterios de unión, está quedando obsoleta en la mayoría de las bases de datos modernas.

No es sólo para mostrar, la sintaxis antigua tiene la posibilidad de ser ambigua cuando se utilizan combinaciones INTERNAS y EXTERNAS en la misma consulta.

Dejame darte un ejemplo.

Supongamos que tiene 3 tablas en su sistema:

Company
Department
Employee

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

Bien, ahora quieres hacer lo siguiente:

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

Entonces haces esto:

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

Tenga en cuenta que el último es una unión interna, para cumplir con el criterio de que solo desea departamentos con personas.

Bien, entonces, ¿qué pasa ahora? Bueno, el problema es que depende del motor de la base de datos, el optimizador de consultas, los índices y las estadísticas de la tabla. Dejame explicar.

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

La razón de esto es que la WHEREcláusula 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 columna Department.ID será NULL y, por lo tanto, cuando se trata de la UNIÓN INTERNA al Empleado, no hay forma de cumplir esa restricción para la fila Empleado, por lo que no será así. aparecer.

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

Entonces la antigua sintaxis es ambigua. No hay forma de especificar lo que desea sin tener que lidiar con sugerencias de consulta, y algunas bases de datos no tienen ninguna manera.

Ingresa la nueva sintaxis, con esta podrás elegir.

Por ejemplo, si desea todas las empresas, como indica 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 la unión entre departamento y empleado se realice como una sola unión y luego une los resultados con las empresas.

Además, digamos que solo desea departamentos que contengan la letra X en su nombre. Nuevamente, con las uniones de estilo antiguo, también corre el riesgo de perder la empresa 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 adicional se utiliza para la unión, pero no es un filtro para toda la fila. Por lo tanto, la fila puede aparecer con información de la empresa, pero puede tener valores NULL en todas las columnas de departamento y empleado de esa fila, porque no hay ningún departamento con una X en el nombre de esa empresa. Esto es difícil con la sintaxis antigua.

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

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

Ahí lo tienes.

LEFT and INNER JOIN es la ola del futuro.

Lasse V. Karlsen avatar May 21 '2009 19:05 Lasse V. Karlsen

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

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)
Andomar avatar May 21 '2009 18:05 Andomar

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 empresas de bases de datos adoptaran el estándar SQL-92.

Entonces, 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.

Dwight T avatar May 21 '2009 20:05 Dwight T

Se prefiere el segundo porque es mucho menos probable que se produzca una unión cruzada accidental al olvidarse de incluir la cláusula where. Una unión sin cláusula on fallará en la verificación de sintaxis, una unión de estilo antiguo sin cláusula Where no fallará, realizará una unión cruzada.

Además, cuando más adelante tengas que unirte 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 usarla.

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

HLGEM avatar May 21 '2009 19:05 HLGEM

Creo que hay algunas buenas razones en esta página para adoptar el segundo método: usar JOINs explícitos. Sin embargo, el factor decisivo es que cuando los criterios JOIN 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, resulta mucho más fácil para el lector comprender lo que está sucediendo.

Alan G avatar Jun 25 '2012 10:06 Alan G