2008-12-09 32 views
471

Después de leerlo, esto es no un duplicado de Explicit vs Implicit SQL Joins. La respuesta puede estar relacionada (o incluso la misma) pero la pregunta es diferente.SQL join: where cláusula vs. on cláusula


¿Cuál es la diferencia y qué debe ir en cada uno?

Si entiendo la teoría correctamente, el optimizador de consultas debería ser capaz de usar ambos indistintamente.

+0

Solo para futuros lectores y su información, debe leer el orden de ejecución de sql. Esto lo ayudaría a entender más precisamente la diferencia subyacente. –

Respuesta

627

No son lo mismo.

Considere estas preguntas:

SELECT * 
FROM Orders 
LEFT JOIN OrderLines ON OrderLines.OrderID=Orders.ID 
WHERE Orders.ID = 12345 

y

SELECT * 
FROM Orders 
LEFT JOIN OrderLines ON OrderLines.OrderID=Orders.ID 
    AND Orders.ID = 12345 

La primera devolverá un pedido y sus líneas, en su caso, para el número de orden de 12345. El segundo devolverá todos los pedidos, pero solo el pedido 12345 tendrá líneas asociadas.

Con un INNER JOIN, las cláusulas son efectivamente equivalente. Sin embargo, el hecho de que sean funcionalmente iguales, ya que producen los mismos resultados, no significa que los dos tipos de cláusulas tengan el mismo significado semántico.

+47

¿obtendrá un mejor rendimiento al poner la cláusula where en la cláusula "on" para una unión interna? – FistOfFury

+67

@FistOfFury Sql Server utiliza un procedimiento optimizador de consultas que compila y evalúa su código para producir el mejor plan de ejecución posible. No es perfecto, pero la mayoría de las veces no importará y obtendrás el mismo plan de ejecución de cualquier manera. –

+7

En Postgres noté que NO eran equivalentes y daban como resultado diferentes planes de consulta. Si usa ON, resultó en el uso de materialize. Si usó WHERE, usó un hash. La materialización tenía un caso peor que era 10 veces más costoso que el hash. Esto estaba usando un conjunto de ID en lugar de una única ID. – JamesHutchison

29

En una unión interna, significan lo mismo. Sin embargo, obtendrás resultados diferentes en una combinación externa dependiendo de si pones la condición de unión en la cláusula WHERE vs ON. Eche un vistazo a this related question y this answer (por mí).

Creo que tiene más sentido tener el hábito de poner siempre la condición de unión en la cláusula ON (a menos que sea una unión externa y realmente la quiere en la cláusula where), ya que hace que sea más clara cualquiera que lea su consulta, a qué condiciones se unen las tablas, y también ayuda a evitar que la cláusula WHERE tenga docenas de líneas.

137

En INNER JOIN s son intercambiables, y el optimizador los reorganizará a voluntad.

En OUTER JOIN s, no son necesariamente intercambiables, dependiendo del lado de la unión del que dependan.

Los puse en cualquier lugar dependiendo de la legibilidad.

+5

[En SQL Server hay un caso de borde donde para uniones internas hace la diferencia] (http://stackoverflow.com/questions/4694281/is-it-better-to-do-an-equi-join-in -the-from-clause-or-where-clause/7967048 # 7967048) –

+0

Probablemente sea mucho más claro en la cláusula Where, especialmente en las expresiones lambda Linq-To-Entities 'Orders.Join (OrderLines, x => x.ID , x => ID de pedido, (o, l) => nuevo {Pedidos = o, Líneas = l}). Dónde (ol => ol.Orders.ID = 12345) ' – Triynko

7

En términos del optimizador, no debería haber ninguna diferencia si define sus cláusulas de unión con ON o WHERE.

Sin embargo, en mi humilde opinión, creo que es mucho más claro utilizar la cláusula ON al realizar uniones. De esta forma, tiene una sección específica de su consulta que dictamina cómo se maneja la unión, en lugar de entremezclarse con el resto de las cláusulas WHERE.

29

La manera de hacerlo es:

siempre ponen las condiciones de combinación en la cláusula on Si usted está haciendo una combinación interna, por lo que no añaden ninguna condiciones en las que la cláusula on, los pusieron en el dónde cláusula

Si está haciendo una combinación a la izquierda, agregue cualquier condición a la cláusula on para la tabla en el lado derecho de la unión. Esto es imprescindible porque agregar una cláusula where que haga referencia al lado derecho de la unión convertirá la unión en una unión interna (con una excepción que se describe a continuación).

La excepción es que cuando busca los registros que no están en una tabla particular, debe agregar la referencia a un identificador único (que nunca es nulo) en la tabla de unión derecha a la cláusula where de esta manera "Donde t2.idfield es nulo". Por lo tanto, la única vez que debe hacer referencia a una tabla en el lado derecho de la combinación es encontrar los registros que no están en la tabla.

+3

Esta es la mejor respuesta que he leído en este hasta aquí. Tiene sentido una vez que tu cerebro entienda que una combinación a la izquierda ** va a ** devolver todas las filas en la tabla de la izquierda y tendrás que filtrarla más tarde. –

-5

esta es mi solución.

SELECT song_ID,songs.fullname, singers.fullname 
FROM music JOIN songs ON songs.ID = music.song_ID 
JOIN singers ON singers.ID = music.singer_ID 
GROUP BY songs.fullname 

Usted debe tener la GROUP BY para conseguir que funcione.

Espero que esta ayuda.

+9

Agrupar solo en songs.fullname mientras selecciona también song_id y singers.fullname va a ser un problema en la mayoría de las bases de datos. – btilly

0

Creo que es el efecto de secuencia de unión. En el caso de unión superior izquierda, SQL do primero se une a la izquierda y luego hace donde se filtra. En el caso de downer, primero busque Orders.ID = 12345 y luego únase.

134
  • no importa para uniones interiores
  • Asuntos para uniones externas

    a. WHERE cláusula: Después de unir. Los registros se filtrarán después de que se haya realizado la unión.

    b. ON cláusula - Antes de unir. Los registros (de la tabla derecha) se filtrarán antes de unirse. Esto puede terminar como nulo en el resultado (desde la unión EXTERIOR).



Ejemplo: Considere las siguientes tablas:

1. documents: 
    | id | name  | 
    --------|-------------| 
    | 1  | Document1 | 
    | 2  | Document2 | 
    | 3  | Document3 | 
    | 4  | Document4 | 
    | 5  | Document5 | 


    2. downloads: 
    | id | document_id | username | 
    |------|---------------|----------| 
    | 1 | 1    | sandeep | 
    | 2 | 1    | simi  | 
    | 3 | 2    | sandeep | 
    | 4 | 2    | reya  | 
    | 5 | 3    | simi  | 

a) Dentro de WHERE cláusula:

SELECT documents.name, downloads.id 
    FROM documents 
    LEFT OUTER JOIN downloads 
     ON documents.id = downloads.document_id 
    WHERE username = 'sandeep' 

For above query the intermediate join table will look like this. 

    | id(from documents) | name   | id (from downloads) | document_id | username | 
    |--------------------|--------------|---------------------|-------------|----------| 
    | 1     | Document1 | 1     | 1   | sandeep | 
    | 1     | Document1 | 2     | 1   | simi  | 
    | 2     | Document2 | 3     | 2   | sandeep | 
    | 2     | Document2 | 4     | 2   | reya  | 
    | 3     | Document3 | 5     | 3   | simi  | 
    | 4     | Document4 | NULL    | NULL  | NULL  | 
    | 5     | Document5 | NULL    | NULL  | NULL  | 

    After applying the `WHERE` clause and selecting the listed attributes, the result will be: 

    | name   | id | 
    |--------------|----| 
    | Document1 | 1 | 
    | Document2 | 3 | 

b) Dentro de JOIN cláusula

SELECT documents.name, downloads.id 
    FROM documents 
    LEFT OUTER JOIN downloads 
     ON documents.id = downloads.document_id 
     AND username = 'sandeep' 

For above query the intermediate join table will look like this. 

    | id(from documents) | name   | id (from downloads) | document_id | username | 
    |--------------------|--------------|---------------------|-------------|----------| 
    | 1     | Document1 | 1     | 1   | sandeep | 
    | 2     | Document2 | 3     | 2   | sandeep | 
    | 3     | Document3 | NULL    | NULL  | NULL  | 
    | 4     | Document4 | NULL    | NULL  | NULL  | 
    | 5     | Document5 | NULL    | NULL  | NULL  | 

Notice how the rows in `documents` that did not match both the conditions are populated with `NULL` values. 

After Selecting the listed attributes, the result will be: 

    | name  | id | 
    |------------|------| 
    | Document1 | 1 | 
    | Document2 | 3 | 
    | Document3 | NULL | 
    | Document4 | NULL | 
    | Document5 | NULL | 
+9

IMO esta es la mejor respuesta porque demuestra claramente lo que está sucediendo "bajo el capó" de las otras respuestas populares. – psrpsrpsr

+2

Aprendí algo nuevo hoy, esta es definitivamente la mejor respuesta que la respuesta más votado. –

0

En SQL, el 'dónde' y la cláusula 'ON', son una especie de condicional Statemants, pero la principal diferencia entre ellos es, el 'dónde' cláusula se utiliza en las sentencias SELECT/Actualizar para especificar las condiciones, mientras que se utiliza la cláusula 'ON' en une, donde se verifica o comprueba si los registros son coincidentes en las tablas de destino y de origen, antes de que las tablas se combinan

por ejemplo: - 'donde'

SELECT * FROM empleado DONDE employee_id = 101

por ejemplo: -. 'ON'

* Hay dos mesas empleado y employee_details, las columnas coincidentes se employee_id *

SELECT * FROM empleado INNER JOIN employee_details EN employee.employee_id = employee_details.employee_id

Esperanza He respondido a su Question.Revert de vuelta para aclaraciones.

+0

Pero podría usar la palabra clave 'WHERE' en lugar de 'ON', ¿o no? http://sqlfiddle.com/#!2/ae5b0/14/0 – Qwerty

0

Para una unión interna, WHERE y ON se pueden usar indistintamente. De hecho, es posible usar ON en una subconsulta correlacionada. Por ejemplo:

update mytable 
set myscore=100 
where exists (
select 1 from table1 
inner join table2 
on (table2.key = mytable.key) 
inner join table3 
on (table3.key = table2.key and table3.key = table1.key) 
... 
) 

Ésta es (en mi humilde opinión) totalmente confuso para un ser humano, y es muy fácil olvidarse de enlazar table1 a nada (porque la tabla "conductor" no tiene un "sobre" cláusula), pero es legal

11

This article explica claramente la diferencia. También explica que "ON joined_condition vs WHERE joined_condition o joined_alias es nulo".

La cláusula WHERE filtra tanto el lado izquierdo como el derecho de JOIN, mientras que la cláusula ON siempre filtrará el lado derecho.

  1. Si siempre desea buscar las filas del lado izquierdo y solo UNIRSE si alguna condición coincide, entonces debe usar la cláusula ON.
  2. Si desea filtrar el producto de unir ambos lados, debe usar la cláusula WHERE.
1

para obtener mejores resultados, las tablas deben tener una columna indexada especial para usar para UNIRSE.

así que si la columna en la que está activado no es una de esas columnas indexadas, entonces sospecho que es mejor mantenerla en DONDE.

por lo que se UNE usando las columnas indexadas, luego después de UNIR, ejecuta la condición en la columna no indexada.

5

Existe una gran diferencia entre cláusula where vs en la cláusula, cuando se trata de la izquierda se unen.

Aquí es ejemplo:

mysql> desc t1; 
+-------+-------------+------+-----+---------+-------+ 
| Field | Type  | Null | Key | Default | Extra | 
+-------+-------------+------+-----+---------+-------+ 
| id | int(11)  | NO |  | NULL |  | 
| fid | int(11)  | NO |  | NULL |  | 
| v  | varchar(20) | NO |  | NULL |  | 
+-------+-------------+------+-----+---------+-------+ 

Hay FID es Identificación de la tabla t2.

mysql> desc t2; 
+-------+-------------+------+-----+---------+-------+ 
| Field | Type  | Null | Key | Default | Extra | 
+-------+-------------+------+-----+---------+-------+ 
| id | int(11)  | NO |  | NULL |  | 
| v  | varchar(10) | NO |  | NULL |  | 
+-------+-------------+------+-----+---------+-------+ 
2 rows in set (0.00 sec) 

consulta en "en la cláusula":

mysql> SELECT * FROM `t1` left join t2 on fid = t2.id AND t1.v = 'K' 
    -> ; 
+----+-----+---+------+------+ 
| id | fid | v | id | v | 
+----+-----+---+------+------+ 
| 1 | 1 | H | NULL | NULL | 
| 2 | 1 | B | NULL | NULL | 
| 3 | 2 | H | NULL | NULL | 
| 4 | 7 | K | NULL | NULL | 
| 5 | 5 | L | NULL | NULL | 
+----+-----+---+------+------+ 
5 rows in set (0.00 sec) 

consulta en "cláusula where":

mysql> SELECT * FROM `t1` left join t2 on fid = t2.id where t1.v = 'K'; 
+----+-----+---+------+------+ 
| id | fid | v | id | v | 
+----+-----+---+------+------+ 
| 4 | 7 | K | NULL | NULL | 
+----+-----+---+------+------+ 
1 row in set (0.00 sec) 

Está claro que, la primera consulta devuelve una registre desde t1 y su fila dependiente desde t2, si hay alguna, para la fila t1.v = 'K'.

La segunda consulta devuelve filas de t1, pero solo para t1.v = 'K' tendrá cualquier fila asociada con ella.

0

Normalmente, el filtrado se procesa en la cláusula WHERE una vez que las dos tablas ya se han unido. Sin embargo, es posible que desee filtrar una o ambas tablas antes de unirse a ellas. es decir, la cláusula where se aplica a todo el conjunto de resultados, mientras que la cláusula on solo se aplica a la combinación en cuestión.