Cláusula INNER JOIN ON vs WHERE

941

Por simplicidad, suponga que todos los campos relevantes son NOT NULL.

Tu puedes hacer:

SELECT
    table1.this, table2.that, table2.somethingelse
FROM
    table1, table2
WHERE
    table1.foreignkey = table2.primarykey
    AND (some other conditions)

Si no:

SELECT
    table1.this, table2.that, table2.somethingelse
FROM
    table1 INNER JOIN table2
    ON table1.foreignkey = table2.primarykey
WHERE
    (some other conditions)

¿Estos dos funcionan de la misma manera MySQL?

JCCyC
fuente
1
@Marco: aquí está
Alexander Malakhov
1
posible duplicado de SQL left join vs múltiples tablas en la línea FROM?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
18
Si he entendido correctamente, la primera variante es la sintaxis implícita ANSI SQL-89 y la segunda variante es la sintaxis de unión explícita ANSI SQL-92. Ambos darán como resultado el mismo resultado en implementaciones de SQL conformes y ambos darán como resultado el mismo plan de consulta en implementaciones de SQL bien hechas. Personalmente prefiero la sintaxis SQL-89, pero muchas personas prefieren la sintaxis SQL-92.
Mikko Rantalainen
11
@Hogan Estaba señalando los nombres oficiales para diferentes sintaxis. Ninguna de las respuestas explicaba explícitamente los nombres completos, así que decidí agregarlos como comentarios. Sin embargo, mi comentario no respondió la pregunta real, así que lo agregué como un comentario, no como una respuesta. (Alta votado respuestas tienen las declaraciones como "INNER JOIN es la sintaxis ANSI" y "implícita sintaxis de combinación ANSI es más viejo", que no dice nada en absoluto, porque ambos son diferentes sintaxis sintaxis ANSI.)
Mikko Rantalainen

Respuestas:

710

INNER JOIN es la sintaxis ANSI que debes usar.

En general, se considera más legible, especialmente cuando une muchas tablas.

También se puede reemplazar fácilmente con un OUTER JOINcuando surja una necesidad.

La WHEREsintaxis está más orientada al modelo relacional.

Un resultado de dos tablas JOINed es un producto cartesiano de las tablas a las que se aplica un filtro que selecciona solo aquellas filas con columnas de unión coincidentes.

Es más fácil ver esto con la WHEREsintaxis.

En cuanto a su ejemplo, en MySQL (y en SQL en general) estas dos consultas son sinónimos.

También tenga en cuenta que MySQL también tiene una STRAIGHT_JOINcláusula.

Con esta cláusula, puede controlar el JOINorden: qué tabla se escanea en el bucle externo y cuál está en el bucle interno.

No puede controlar esto en MySQL usando la WHEREsintaxis.

Quassnoi
fuente
10
Gracias Quassnoi. Tienes muchos detalles en tu ans; ¿Es justo decir que "sí, esas consultas son equivalentes, pero debería usar unión interna porque es más legible y más fácil de modificar"?
allyourcode
8
@allyourcode: para Oracle, SQL Server, MySQLy PostgreSQL- sí. Para otros sistemas, probablemente también, pero es mejor que lo verifique.
Quassnoi
13
FWIW, el uso de comas con condiciones de unión en la WHEREcláusula también está en el estándar ANSI.
Bill Karwin el
1
@Bill Karwin: la JOINpalabra clave no fue parte de los estándares de propiedad hasta el pasado más reciente de lo que parece. Se abrió camino Oraclesolo en versión 9y PostgreSQLen versión 7.2(ambos lanzados en 2001). La aparición de esta palabra clave fue parte de ANSIla adopción estándar, y es por eso que esta palabra clave generalmente está asociada ANSI, a pesar de que esta última también admite coma como sinónimo CROSS JOIN.
Quassnoi
99
Sin embargo, ANSI SQL-89 especificó uniones que se deben hacer con comas y condiciones en una WHEREcláusula (sin condiciones, una unión es equivalente a una unión cruzada, como usted dijo). ANSI SQL-92 agregó la JOINpalabra clave y la sintaxis relacionada, pero la sintaxis de estilo de coma todavía es compatible con la compatibilidad con versiones anteriores.
Bill Karwin el
182

Otros han señalado que INNER JOINayuda a la legibilidad humana, y esa es una prioridad, estoy de acuerdo.
Permítanme intentar explicar por qué la sintaxis de combinación es más legible.

Una SELECTconsulta básica es esta:

SELECT stuff
FROM tables
WHERE conditions

La SELECTcláusula nos dice qué estamos recuperando; la FROMcláusula nos dice dónde estamos recibiendo desde, y la WHEREcláusula nos dice , que los que estamos recibiendo.

JOIN es una declaración sobre las tablas, cómo se unen (conceptualmente, en realidad, en una sola tabla).

Cualquier elemento de consulta que controle las tablas, de donde obtenemos cosas, pertenece semánticamente a la FROMcláusula (y, por supuesto, ahí es donde JOINvan los elementos). Poner elementos de unión en la WHEREcláusula combina el cuál y el de dónde , por eso JOINse prefiere la sintaxis.

Carl Manaster
fuente
77
Gracias por aclarar por qué se prefiere la unión interna Carl. Creo que su respuesta fue implícita en los demás, pero explícito suele ser mejor (sí, soy un fanático de Python).
allyourcode el
2
La semántica de ON y WHERE significa que para JOINs después de la última OUTER JOIN no importa cuál use. Aunque a caracterizar EN como parte de la unión, es también un filtrado después de un producto cartesiano. Tanto ON como WHERE filtran un producto cartesiano. Pero ya sea ENCENDIDO o una subselección con DONDE debe usarse antes de la última UNIÓN EXTERNA. (JOIN no son "en" pares de columnas Cualquier dos tablas se pueden unir bajo cualquier condición Eso es sólo una manera de interpretar acompaña en igualdad de columnas en concreto...)
philipxy
Incluso cuando utilice WHERE con el mismo efecto que INNER JOIN, mencionará sus dos tablas en la parte FROM de la consulta. Básicamente, todavía estás insinuando de dónde estás obteniendo tus datos en la cláusula FROM, así que supongo que no puedes decir que necesariamente "combina el qué y el de dónde"
cybergeek654
@ArsenKhachaturyan El hecho de que se use una palabra clave o un identificador en el texto no significa que sea un código y necesite un formato de código. Esa es una opción de formato que podría ser de cualquier manera y si es razonable editar aquí, entonces es justificable que cada publicación se edite constantemente al otro formato, es decir, no es justificable. (Además, el formato de código por palabra en línea puede ser difícil de leer). Lo mismo para los saltos de párrafo aquí, no son particularmente claros. Lo mismo con 'which' vs 'that'. Y los nombres de los lenguajes de programación no deben estar en formato de código. PD: agregó un salto de línea por error.
philipxy
@philipxy como mencionó "no significa ...", pero obviamente eso tampoco significa que no se puede marcar con la palabra clave de código. Sí, se debe elegir, pero se realizan muchas publicaciones sin saberlo. Por lo tanto, mi decisión de hacer los cambios no tiene la intención de romper nada, sino hacerlo más legible. Si notó alguna interrupción después de formatear los cambios, lo siento, y obviamente puede revertir dichos cambios.
Arsen Khachaturyan
143

Aplicación de declaraciones condicionales en ON / WHERE

Aquí he explicado los pasos de procesamiento de consultas lógicas.


Referencia: Inside Microsoft® SQL Server ™ 2005 T-SQL Querying
Editor: Microsoft Press
Pub Fecha: 07 de marzo de 2006
Imprimir ISBN-10: 0-7356-2313-9
Imprimir ISBN-13: 978-0-7356-2313-2
Páginas: 640

Dentro de Microsoft® SQL Server ™ 2005 Consulta T-SQL

(8)  SELECT (9) DISTINCT (11) TOP <top_specification> <select_list>
(1)  FROM <left_table>
(3)       <join_type> JOIN <right_table>
(2)       ON <join_condition>
(4)  WHERE <where_condition>
(5)  GROUP BY <group_by_list>
(6)  WITH {CUBE | ROLLUP}
(7)  HAVING <having_condition>
(10) ORDER BY <order_by_list>

El primer aspecto notable de SQL que es diferente de otros lenguajes de programación es el orden en que se procesa el código. En la mayoría de los lenguajes de programación, el código se procesa en el orden en que está escrito. En SQL, la primera cláusula que se procesa es la cláusula FROM, mientras que la cláusula SELECT, que aparece primero, se procesa casi en último lugar.

Cada paso genera una tabla virtual que se utiliza como entrada para el siguiente paso. Estas tablas virtuales no están disponibles para la persona que llama (aplicación cliente o consulta externa). Solo la tabla generada por el paso final se devuelve a la persona que llama. Si una determinada cláusula no se especifica en una consulta, simplemente se omite el paso correspondiente.

Breve descripción de las fases de procesamiento de consultas lógicas

No se preocupe demasiado si la descripción de los pasos no parece tener mucho sentido por ahora. Estos se proporcionan como referencia. Las secciones que vienen después del ejemplo de escenario cubrirán los pasos con mucho más detalle.

  1. FROM: se realiza un producto cartesiano (unión cruzada) entre las dos primeras tablas de la cláusula FROM y, como resultado, se genera la tabla virtual VT1.

  2. ON: el filtro ON se aplica a VT1. Solo las filas para las cuales <join_condition>es VERDADERO se insertan en VT2.

  3. OUTER (join): si se especifica un OUTER JOIN (a diferencia de CROSS JOIN o INNER JOIN), las filas de la tabla o tablas preservadas para las que no se encontró una coincidencia se agregan a las filas de VT2 como filas externas, generando VT3. Si aparecen más de dos tablas en la cláusula FROM, los pasos 1 a 3 se aplican repetidamente entre el resultado de la última unión y la siguiente tabla en la cláusula FROM hasta que se procesen todas las tablas.

  4. WHERE: el filtro WHERE se aplica a VT3. Solo las filas para las que <where_condition>es VERDADERO se insertan en VT4.

  5. GROUP BY: las filas de VT4 se organizan en grupos según la lista de columnas especificada en la cláusula GROUP BY. Se genera VT5.

  6. CUBO | ROLLUP: los supergrupos (grupos de grupos) se agregan a las filas desde VT5, generando VT6.

  7. HAVING: el filtro HAVING se aplica a VT6. Solo los grupos para los que <having_condition>es VERDADERO se insertan en VT7.

  8. SELECCIONAR: se procesa la lista SELECCIONAR, generando VT8.

  9. DISTINCT: las filas duplicadas se eliminan de VT8. Se genera VT9.

  10. ORDER BY: las filas de VT9 se ordenan según la lista de columnas especificada en la cláusula ORDER BY. Se genera un cursor (VC10).

  11. ARRIBA: El número o porcentaje especificado de filas se selecciona desde el comienzo de VC10. La tabla VT11 se genera y se devuelve a la persona que llama.



Por lo tanto, (INNER JOIN) ON filtrará los datos (el recuento de datos de VT se reducirá aquí mismo) antes de aplicar la cláusula WHERE. Las siguientes condiciones de unión se ejecutarán con datos filtrados que mejoran el rendimiento. Después de eso, solo la condición WHERE aplicará condiciones de filtro.

(La aplicación de declaraciones condicionales en ON / WHERE no hará mucha diferencia en algunos casos. Esto depende de cuántas tablas haya unido y el número de filas disponibles en cada tabla de unión)

rafidheen
fuente
10
"Por lo tanto, (INNER JOIN) ON filtrará los datos (el recuento de datos de VT se reducirá aquí mismo) antes de aplicar la cláusula WHERE". No necesariamente. El artículo trata sobre el orden lógico de procesamiento. Cuando dice que una implementación particular hará una cosa antes que otra, está hablando del orden de procesamiento implementado . Las implementaciones pueden realizar las optimizaciones que deseen, siempre que el resultado sea el mismo que si la implementación siguiera el orden lógico. Joe Celko ha escrito mucho sobre esto en Usenet.
Mike Sherrill 'Cat Recall'
@rafidheen "(INNER JOIN) ON filtrará los datos ... antes de aplicar la cláusula WHERE ... que mejora el rendimiento". Buen punto. "Después de eso, solo la condición WHERE aplicará condiciones de filtro" ¿Qué pasa con la cláusula HAVING?
James
@James Esa afirmación de rafidheen está mal. Consulte 'optimización de combinación' en el manual. También mis otros comentarios en esta página. (Y MikeSherrill'CatRecall''s.) Estas descripciones "lógicas" describen el valor del resultado, no cómo se calcula realmente. Y no se garantiza que dicho comportamiento de implementación no cambie.
philipxy
67

La sintaxis de unión ANSI implícita es más antigua, menos obvia y no recomendada.

Además, el álgebra relacional permite la intercambiabilidad de los predicados en la WHEREcláusula y el INNER JOIN, por lo que incluso las INNER JOINconsultas conWHERE cláusulas pueden hacer que el optimizador reorganice los predicados.

Le recomiendo que escriba las consultas de la manera más fácil posible.

Algunas veces esto incluye hacer lo INNER JOINrelativamente "incompleto" y poner algunos de los criterios en elWHERE simplemente para hacer que las listas de criterios de filtrado sean más fáciles de mantener.

Por ejemplo, en lugar de:

SELECT *
FROM Customers c
INNER JOIN CustomerAccounts ca
    ON ca.CustomerID = c.CustomerID
    AND c.State = 'NY'
INNER JOIN Accounts a
    ON ca.AccountID = a.AccountID
    AND a.Status = 1

Escribir:

SELECT *
FROM Customers c
INNER JOIN CustomerAccounts ca
    ON ca.CustomerID = c.CustomerID
INNER JOIN Accounts a
    ON ca.AccountID = a.AccountID
WHERE c.State = 'NY'
    AND a.Status = 1

Pero depende, por supuesto.

Cade Roux
fuente
16
Tu primer fragmento definitivamente lastima más mi cerebro. ¿Alguien realmente hace eso? Si conozco a alguien que hace eso, ¿está bien que lo golpee en la cabeza?
allyourcode el
3
Localizo los criterios donde tiene más sentido. Si me estoy uniendo a una tabla de búsqueda de instantáneas temporalmente consistente (y no tengo una vista o UDF que imponga la selección de una fecha válida), incluiré la fecha efectiva en la unión y no en el DÓNDE porque es menos probable que se elimine accidentalmente.
Cade Roux
14
@allyourcode: aunque es raro ver este tipo de sintaxis de unión en INNER JOINs, es bastante común para RIGHT JOINs y LEFT JOINS: la especificación de más detalles en el predicado de unión elimina la necesidad de una subconsulta y evita que las uniones externas se vuelvan inadvertidamente en uniones internas. (Aunque estoy de acuerdo en que para INNER JOINs casi siempre ponía c.State = 'NY' en la cláusula WHERE)
Dave Markle
1
@allyourcode ¡definitivamente hago eso! Y estoy de acuerdo con Cade. Tengo curiosidad por saber si hay una razón decente para no hacerlo
Arth
31

Las uniones implícitas (que es lo que se conoce como su primera consulta) se vuelven mucho más confusas, difíciles de leer y difíciles de mantener una vez que necesita comenzar a agregar más tablas a su consulta. Imagine hacer esa misma consulta y tipo de unión en cuatro o cinco tablas diferentes ... es una pesadilla.

Usar una unión explícita (su segundo ejemplo) es mucho más legible y fácil de mantener.

mate b
fuente
48
No podría estar más en desacuerdo. La sintaxis de JOIN es extremadamente prolija y difícil de organizar. Tengo muchas consultas uniendo 5, 10, incluso 15 tablas usando las uniones de la cláusula WHERE y son perfectamente legibles. Reescribir dicha consulta utilizando una sintaxis JOIN da como resultado un desorden confuso. Lo que demuestra que no hay una respuesta correcta a esta pregunta y que depende más de con qué se sienta cómodo.
Noah Yetter
33
Noah, creo que podrías ser una minoría aquí.
matt b
2
Tengo +1 para Matt y Noah. Me gusta la diversidad :). Puedo ver de dónde viene Noah; internal join no agrega nada nuevo al lenguaje, y definitivamente es más detallado. Por otro lado, puede hacer que su condición de 'dónde' sea mucho más corta, lo que generalmente significa que es más fácil de leer.
allyourcode el
55
Supongo que cualquier DBMS sano traduciría las dos consultas en el mismo plan de ejecución; sin embargo, en realidad, cada DBMS es diferente y la única forma de saberlo con certeza es examinar el plan de ejecución (es decir, deberá probarlo usted mismo).
mate b
¿Es cierto como @rafidheen sugirió en otra respuesta (la que tiene la secuencia detallada de ejecución de SQL) que las UNIONES se filtran de una en una, reduciendo el tamaño de las operaciones de combinación en comparación con una combinación cartesiana completa de 3 o más tablas, con ¿El filtro WHERE se aplica retroactivamente? Si es así, sugeriría que JOIN ofrece una mejora del rendimiento (así como ventajas en las combinaciones izquierda / derecha, como también se señaló en otra respuesta).
James
26

También señalaré que el uso de la sintaxis anterior está más sujeto a errores. Si utiliza uniones internas sin una cláusula ON, obtendrá un error de sintaxis. Si usa la sintaxis anterior y olvida una de las condiciones de unión en la cláusula where, obtendrá una unión cruzada. Los desarrolladores a menudo arreglan esto agregando la palabra clave distinta (en lugar de arreglar la unión porque todavía no se dan cuenta de que la unión en sí está rota), lo que puede parecer que soluciona el problema, pero ralentizará la consulta considerablemente.

Además, para el mantenimiento si tiene una unión cruzada en la sintaxis anterior, ¿cómo sabrá el mantenedor si quería tener una (hay situaciones en las que se necesitan uniones cruzadas) o si fue un accidente que debería solucionarse?

Permítame señalarle esta pregunta para ver por qué la sintaxis implícita es mala si usa combinaciones izquierdas. Sybase * = a Ansi Standard con 2 tablas externas diferentes para la misma tabla interna

Además (discurso personal aquí), el estándar que usa las uniones explícitas tiene más de 20 años, lo que significa que la sintaxis de unión implícita ha quedado desactualizada durante esos 20 años. ¿Escribiría el código de la aplicación utilizando una sintaxis que ha estado desactualizada durante 20 años? ¿Por qué quieres escribir el código de la base de datos que es?

HLGEM
fuente
3
@HLGEM: Si bien estoy completamente de acuerdo en que las uniones explícitas son mejores, hay casos en los que solo necesita usar la sintaxis anterior. Un ejemplo del mundo real: ANSI JOIN entró en Oracle solo en la versión 9i que se lanzó en 2001, y hasta hace solo un año (16 años desde el momento en que se publicó el estándar) tuve que soportar un montón de instalaciones 8i para las que teníamos para lanzar actualizaciones críticas. No quería mantener dos conjuntos de actualizaciones, por lo que desarrollamos y probamos las actualizaciones en todas las bases de datos, incluida 8i, lo que significaba que no podíamos usar ANSI JOIN.
Quassnoi
+1 punto interesante cuando señala que la sintaxis sin INNER JOIN es más propensa a errores. Estoy confundido acerca de su última oración cuando dice "... el estándar que usa las uniones explícitas tiene 17 años". entonces, ¿sugieres usar la palabra clave INNER JOIN o no?
Marco Demaio
1
@Marco Demaio, sí, siempre use INNER JOIN o JOIN (estos dos son iguales) o LEFT JOIN o RIGHT JOIN o CROSS JOIN y nunca use las comas implícitas.
HLGEM
2
"¿Por qué quieres escribir el código de la base de datos que tiene [20 años]?" - Noté que escribes SQL usando lo HAVINGque ha estado 'desactualizado' desde que SQL comenzó a admitir tablas derivadas. También me doy cuenta de que no lo usas NATURAL JOIN, aunque yo diría que está INNER JOIN"desactualizado". Sí, tiene sus razones (¡no es necesario que las repita aquí!): Mi punto es que aquellos a quienes les gusta usar la sintaxis anterior también tienen sus razones y la edad relativa de la sintaxis es de poca o ninguna relevancia.
cuando el
1
DONDE todavía está en el estándar (muéstrame dónde no está). Entonces, nada anticuado, aparentemente. Además, "en lugar de arreglar la unión" me muestra un desarrollador que debe mantenerse alejado de los DBMS en general, muy lejos.
Jürgen A. Erhard
12

Tienen un significado diferente legible para los humanos.

Sin embargo, dependiendo del optimizador de consultas, pueden tener el mismo significado para la máquina.

Siempre debe codificar para que sea legible.

Es decir, si esta es una relación incorporada, use la unión explícita. si está haciendo coincidir datos débilmente relacionados, use la cláusula where.

John Gietzen
fuente
11

El estándar SQL: 2003 cambió algunas reglas de precedencia, por lo que una declaración JOIN tiene prioridad sobre una unión "coma". En realidad, esto puede cambiar los resultados de su consulta dependiendo de cómo se configure. Esto causa algunos problemas para algunas personas cuando MySQL 5.0.12 cambió a adherirse al estándar.

Entonces, en su ejemplo, sus consultas funcionarían igual. Pero si agregó una tercera tabla: SELECT ... FROM table1, table2 JOIN table3 ON ... WHERE ...

Antes de MySQL 5.0.12, table1 y table2 se unirían primero, luego table3. Ahora (5.0.12 y en adelante), table2 y table3 se unen primero, luego table1. No siempre cambia los resultados, pero puede hacerlo y es posible que ni siquiera se dé cuenta.

Ya nunca uso la sintaxis "coma", optando por su segundo ejemplo. De todos modos, es mucho más legible, las condiciones de UNIÓN son con las UNIONES, no separadas en una sección de consulta separada.

Brent Baisley
fuente
El SQL estándar no cambió. MySQL estaba mal y ahora tiene razón. Vea el manual de MySQL.
philipxy
4

Sé que estás hablando de MySQL, pero de todos modos: en Oracle 9, las uniones explícitas y las implícitas generarían diferentes planes de ejecución. AFAIK que se ha resuelto en Oracle 10+: ya no hay tanta diferencia.

João Marcus
fuente
1

La sintaxis de unión ANSI es definitivamente más portátil.

Estoy pasando por una actualización de Microsoft SQL Server, y también mencionaría que la sintaxis = * y * = para las uniones externas en SQL Server no es compatible (sin el modo de compatibilidad) para el servidor sql 2005 y posterior.

Benzo
fuente
2
Incluso en SQL Server 2000, = y = podrían dar resultados incorrectos y nunca deberían usarse.
HLGEM
2
*=y =*nunca fueron ANSI y nunca fueron una buena notación. Por eso era necesario ON - para combinaciones externas en ausencia de subselects (que consiguió añadió al mismo tiempo, por lo que no son realmente necesarios en CRUZ Y uniones internas.)
philipxy
1

Si a menudo está programando procedimientos almacenados dinámicos, se enamorará de su segundo ejemplo (usando where). Si tiene varios parámetros de entrada y mucho desorden morfo, entonces esa es la única manera. De lo contrario, ambos ejecutarán el mismo plan de consulta, por lo que definitivamente no hay una diferencia obvia en las consultas clásicas.

Kviz Majster
fuente