SQL присоединиться: где предложение vs. по п

голоса
483

Прочитав его, это не дубликат Явные против неявных SQL присоединяется . Ответ может быть связан (или даже тот же) , но вопрос по - другому.


В чем разница и что должно пойти в каждом?

Если я понимаю теорию правильно, оптимизатор запросов должен быть в состоянии использовать как взаимозаменяемые.

Задан 09/12/2008 в 21:14
источник пользователем
На других языках...                            


17 ответов

голоса
640

Они не одно и то же.

Рассмотрим эти вопросы:

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

а также

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

Первый возвращает порядок и его линии, если таковые имеются, по номеру заказа 12345. Второй возвращают все заказы, но только для того 12345будет иметь какую - либо линию , связанную с ним.

С INNER JOIN, что положения являются фактически эквивалентны. Тем не менее, только потому , что они функционально же, в том , что они дают одинаковые результаты, не означает , что эти два вида положений имеют одинаковую смысловую.

Ответил 09/12/2008 в 21:21
источник пользователем

голоса
154
  • Не имеет значения для внутренних соединений
  • Вопросы для внешних соединений

    а. WHEREпункт: После присоединения. Записи будут отфильтрованы после присоединиться имевшее место.

    б. ONпункт - До прихода. Записи (из таблицы справа) будет фильтроваться до прихода. Это может закончиться как нуль в результате (с OUTER присоединиться).



Пример : Рассмотрим следующие таблицы:

    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     |

а) Внутри WHEREпункта:

  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  | 

б) Внутри JOINпункта

  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 | 
Ответил 07/01/2014 в 21:54
источник пользователем

голоса
137

На INNER JOINх они взаимозаменяемы, и оптимизатор будет переставлять их по своему желанию.

На OUTER JOINх, они не обязательно являются взаимозаменяемыми, в зависимости от того, какая сторона объединения они зависят от.

Я положил их в любом месте, в зависимости от читаемости.

Ответил 09/12/2008 в 21:21
источник пользователем

голоса
30

Как мне сделать это:

Всегда ставить условие соединения в предложении на Если вы делаете внутреннее соединение, поэтому не добавляйте где условия к о п, положить их в ИНЕКЕ

Если вы делаете левый присоединиться, добавлять где условия к о п для таблицы в правой части соединения. Это необходимо потому, что добавление, где положение, которое ссылается на правую сторону объединения будет преобразовывать зарегистрироваться, чтобы внутреннее соединение (за одним исключением описанного ниже).

Исключением является то, что, когда вы ищете для записей, которые не в конкретной таблице, вы бы добавить Refernce к уникальному идентификатору (то есть никогда не нуль) в правом присоединиться таблицы, где положение таким образом, «где Т2. idfield равно нулю». Поэтому единственный раз, когда вы должны ссылаться на таблицу на правой стороне соединения, чтобы найти те записи, которые не находятся в таблице.

Ответил 09/12/2008 в 21:57
источник пользователем

голоса
29

На внутреннем соединении, они имеют в виду то же самое. Однако вы получите разные результаты внешнего соединения в зависимости от того, если вы поставите условие объединения в WHERE против оговорки ON. Взгляните на этом связанный с этим вопрос и этот ответ (на меня).

Я думаю, что это имеет больше смысла, чтобы быть в привычку всегда поставить условие объединения в предложении ON (если это не внешнее соединение, и вы на самом деле хотите в ИНЕКЕ), как это делает его более ясным для тех, кто читает ваш запрос какие условия столы соединены на, а также помогает предотвратить условие WHERE от того, десятки линий длиной.

Ответил 09/12/2008 в 21:20
источник пользователем

голоса
12

В этой статье четко объясняет разницу. Это также объясняет «ON joined_condition против ГДЕ joined_condition или joined_alias равна нулю».

ИНЕКЕ фильтры как левая и правая стороны соединения, в то время как положение ON всегда будет фильтровать только по правой стороне.

  1. Если вы хотите всегда получать левые боковые ряды и только JOIN, если какое-либо условие совпадает, то вы должны в положение ON.
  2. Если вы хотите, чтобы фильтровать продукт присоединения с обеих сторон, то вы должны использовать предложение WHERE.
Ответил 25/05/2014 в 15:20
источник пользователем

голоса
7

С точки зрения оптимизатора, он не должен сделать разницу вы определить, будут ли ваши присоединиться положения с ON или WHERE.

Однако, ИМХО, я думаю, что это гораздо яснее использовать положение ON при выполнении соединения. Таким образом, у вас есть конкретный раздел вам запрос, который определяет, как объединение обрабатывается по сравнению перемешано с остальным ИНЕК.

Ответил 09/12/2008 в 21:21
источник пользователем

голоса
5

Существует большая разница между ИНЕК VS. на пункте , когда речь идет налево присоединиться.

Вот пример:

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

Там груда является идентификатор таблицы 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)

Запрос на «по статье»:

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)

Запрос на «где п»:

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)

Понятно, что первый запрос возвращает записи из t1 и зависимый строки из t2, если таковые имеются, для ряда t1.v = «K».

Второй запрос возвращает строку из t1, но только для t1.v = «K» будет иметь любую строку, связанную с ним.

Ответил 13/03/2016 в 06:31
источник пользователем

голоса
1

Обычно, фильтрация обрабатывается в предложении, где когда две таблицы уже присоединились. Вполне возможно, что, хотя вы можете отфильтровать один или оба из таблиц, прежде чем присоединиться к ним. то есть положение, где применяется ко всему результирующего набора, тогда как на пункте относится только к присоединиться к вопросу.

Ответил 16/02/2018 в 05:29
источник пользователем

голоса
1

за лучшие таблицы производительности должны иметь специальный индексированный столбец, используемый для соединения.

поэтому, если столбец вы кондиционировать на это не один из тех индексированных столбцов, то я подозреваю, что лучше держать его в WHERE.

так что вы JOIN с помощью индексированных столбцов, то после запуска РЕГИСТРИРУЙТЕСЬ условие на доли не индексируются столбца.

Ответил 12/12/2014 в 21:10
источник пользователем

голоса
0

Вы пытаетесь объединить данные данных или фильтр?

Для удобства чтения, что делает наиболее целесообразно изолировать эти случаи использования в положение ON и WHERE соответственно.

  • объединения данных в ON
  • фильтровать данные в том, где

Это может стать очень трудно читать запрос, где условие JOIN и условие фильтрации существуют в ИНЕКЕ.

С точки зрения производительности вы не должны видеть разницу, хотя различные типы SQL иногда обрабатывать планирования запросов по- разному , так что может быть стоит попробовать ¯\_(ツ)_/¯(Помните о кэшировании осуществления скорость запроса)

Также как и другие отметили, если вы используете внешнее соединение, вы получите разные результаты, если вы поместите условие фильтра в предложении ON, потому что это только эффекты одной из таблиц.

Я написал более глубокий пост об этом здесь: https://dataschool.com/learn/difference-between-where-and-on-in-sql

Ответил 30/04/2019 в 02:17
источник пользователем

голоса
0

Давайте рассмотрим эти таблицы:

A

id | SomeData

В

id | id_A | SomeOtherData

id_A будучи внешним ключом к таблице A

Writting этот запрос:

SELECT *
FROM A
LEFT JOIN B
ON A.id = B.id_A;

Обеспечит этот результат:

/ : part of the result
                                       B
                      +---------------------------------+
            A         |                                 |
+---------------------+-------+                         |
|/////////////////////|///////|                         |
|/////////////////////|///////|                         |
|/////////////////////|///////|                         |
|/////////////////////|///////|                         |
|/////////////////////+-------+-------------------------+
|/////////////////////////////|
+-----------------------------+

Что в А, но не в B означает, что нулевые значения для B.


Теперь давайте рассмотрим конкретную часть в B.id_A, и выделить его из предыдущего результата:

/ : part of the result
* : part of the result with the specific B.id_A
                                       B
                      +---------------------------------+
            A         |                                 |
+---------------------+-------+                         |
|/////////////////////|///////|                         |
|/////////////////////|///////|                         |
|/////////////////////+---+///|                         |
|/////////////////////|***|///|                         |
|/////////////////////+---+---+-------------------------+
|/////////////////////////////|
+-----------------------------+

Writting этот запрос:

SELECT *
FROM A
LEFT JOIN B
ON A.id = B.id_A
AND B.id_A = SpecificPart;

Обеспечит этот результат:

/ : part of the result
* : part of the result with the specific B.id_A
                                       B
                      +---------------------------------+
            A         |                                 |
+---------------------+-------+                         |
|/////////////////////|       |                         |
|/////////////////////|       |                         |
|/////////////////////+---+   |                         |
|/////////////////////|***|   |                         |
|/////////////////////+---+---+-------------------------+
|/////////////////////////////|
+-----------------------------+

Потому что это снимает в внутреннее соединение значения, которые не в B.id_A = SpecificPart


Теперь давайте изменим запрос к этому:

SELECT *
FROM A
LEFT JOIN B
ON A.id = B.id_A
WHERE B.id_A = SpecificPart;

В результате в настоящее время:

/ : part of the result
* : part of the result with the specific B.id_A
                                       B
                      +---------------------------------+
            A         |                                 |
+---------------------+-------+                         |
|                     |       |                         |
|                     |       |                         |
|                     +---+   |                         |
|                     |***|   |                         |
|                     +---+---+-------------------------+
|                             |
+-----------------------------+

Потому что весь результат фильтрует против B.id_A = SpecificPartудаления частей B.id_A = NULL, которые находятся в A, которые не являются в B

Ответил 12/04/2019 в 10:03
источник пользователем

голоса
0

Я думаю , что это различие может быть лучше объяснены с помощью логической последовательности операций в SQL , которая, упрощается:

  • FROM (Включая соединения)
  • WHERE
  • GROUP BY
  • Скопления
  • HAVING
  • WINDOW
  • SELECT
  • DISTINCT
  • UNION, INTERSECT,EXCEPT
  • ORDER BY
  • OFFSET
  • FETCH

Соединения не являются разделом выбора заявления, но оператор внутри FROM. Как таковые, все ONположения , относящиеся к соответствующему JOINоператору иметь «уже произошло» логически к тому времени логической обработки достигает WHEREпункт. Это означает , что в случае включения LEFT JOIN, например, внешнее соединение - х семантики уже случились к тому времени WHEREприменяется статья.

Я объяснил следующий пример более подробно в этом блоге . При выполнении этого запроса:

SELECT a.actor_id, a.first_name, a.last_name, count(fa.film_id)
FROM actor a
LEFT JOIN film_actor fa ON a.actor_id = fa.actor_id
WHERE film_id < 10
GROUP BY a.actor_id, a.first_name, a.last_name
ORDER BY count(fa.film_id) ASC;

LEFT JOINНа самом деле не имеет никакого полезного эффекта, потому что даже если актер не играл в фильме, актер будет фильтроваться, как его FILM_IDбудет NULLи WHEREстатья будет фильтровать такую строку. В результате получается нечто вроде:

ACTOR_ID  FIRST_NAME  LAST_NAME  COUNT
--------------------------------------
194       MERYL       ALLEN      1
198       MARY        KEITEL     1
30        SANDRA      PECK       1
85        MINNIE      ZELLWEGER  1
123       JULIANNE    DENCH      1

Т.е. так же , как если бы мы присоединились к внутренним две таблицы. Если мы перемещаем предикат фильтра в ONпредложении, теперь становится критерием для внешнего соединения:

SELECT a.actor_id, a.first_name, a.last_name, count(fa.film_id)
FROM actor a
LEFT JOIN film_actor fa ON a.actor_id = fa.actor_id
  AND film_id < 10
GROUP BY a.actor_id, a.first_name, a.last_name
ORDER BY count(fa.film_id) ASC;

Значение результата будет содержать актер без каких-либо фильмов или без каких-либо фильмов с FILM_ID < 10

ACTOR_ID  FIRST_NAME  LAST_NAME     COUNT
-----------------------------------------
3         ED          CHASE         0
4         JENNIFER    DAVIS         0
5         JOHNNY      LOLLOBRIGIDA  0
6         BETTE       NICHOLSON     0
...
1         PENELOPE    GUINESS       1
200       THORA       TEMPLE        1
2         NICK        WAHLBERG      1
198       MARY        KEITEL        1

Короче

Всегда надевайте свой предикат, где это имеет наибольший смысл, логически.

Ответил 09/04/2019 в 13:37
источник пользователем

голоса
0

Для внутреннего соединения, WHEREи ONмогут быть использованы как взаимозаменяемые. На самом деле, можно использовать ONв коррелированных подзапросов. Например:

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)
...
)

Это (ИМХО) совершенно сбивает с толку человека, и это очень легко забыть связать table1к чему - либо (потому что «водитель» таблица не имеет «на» положение), но это законно.

Ответил 16/05/2014 в 23:40
источник пользователем

голоса
0

В SQL, положение в «WHERE» и «ON», своего рода условного Statemants, но главное различие между ними, «где» пункт используется в Select / Update отчетности для уточнения условий, в то время как п «на» используется в соединениях, где он проверяет или чеки, если отчеты подбираются в целевых и исходных таблиц, перед Таблицы Регистрация

Например: - «где»

SELECT * FROM сотрудника WHERE employee_id = 101

Например: - 'ON'

* Есть две таблицы сотрудников и employee_details, совпадающие столбцы EMPLOYEE_ID. *

SELECT * FROM сотрудник INNER JOIN employee_details ON employee.employee_id = employee_details.employee_id

Надеюсь, я ответил на ваш Question.Revert назад для уточнений.

Ответил 05/02/2014 в 11:57
источник пользователем

голоса
0

Я думаю, что это объединение последовательности эффект. В верхнем левом углу объединить дело, SQL сделать левый присоединиться к первой, а затем сделать где фильтр. В случае Даунер найти Orders.ID = 12345 первый, а затем сделать присоединиться.

Ответил 07/01/2014 в 04:49
источник пользователем

голоса
-5

это мое решение.

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

Вы должныGROUP BY , чтобы заставить его работать.

Надеюсь, что это поможет.

Ответил 26/04/2010 в 08:53
источник пользователем

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more