2008-12-09 7 views
471

После прочтения это не дубликат Explicit vs Implicit SQL Joins. Ответ может быть связан (или даже тот же), но вопрос отличается.SQL join: where clause vs. on


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

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

+0

Для будущих читателей и вашей информации вы должны прочитать порядок выполнения sql. Это поможет вам более точно понять основную разницу. – 2017-01-20 12:19:25

ответ

627

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

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

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, пункты фактически эквивалент. Однако только потому, что они функционально одинаковы, поскольку они дают одни и те же результаты, это не означает, что два вида предложений имеют одинаковый смысловой смысл.

+47

вы получите лучшую производительность, поставив предложение where в предложение «on» для внутреннего соединения? – FistOfFury 2012-12-07 16:01:36

+67

@FistOfFury Sql Server использует процедуру оптимизатора запросов, которая компилирует и оценивает ваш код для создания наилучшего плана выполнения, который он может выполнить. Это не идеально, но в большинстве случаев это не имеет значения, и вы получите тот же план выполнения в любом случае. – 2012-12-07 17:29:34

+7

В Postgres я отметил, что они НЕ эквивалентны и привели к разным запросам. Если вы используете ON, это привело к использованию материализации. Если вы использовали WHERE, он использовал хэш. В материализовании был худший случай, который был в 10 раз дороже, чем хэш. Это использовало набор идентификаторов, а не один идентификатор. – JamesHutchison 2016-03-29 17:15:39

29

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

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

137

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

OUTER JOIN s, они не обязательно взаимозаменяемы, в зависимости от того, на какой стороне соединения они зависят.

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

7

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

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

29

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

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

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

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

-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, чтобы заставить его работать.

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

0

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

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

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

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

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

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 | 
0

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

Для примера: - «WHERE»

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

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

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

SELECT * FROM работника INNER JOIN employee_details ON employee.employee_id = employee_details.employee_id

Надежда Я ответил на ваш Question.Revert назад для уточнений.

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 к чему-либо (потому что «водитель» таблицы не имеют «на» п), но это законно.

11

This article ясно объясняет разницу. Он также объясняет «ON join_condition vs WHERE join_condition или join_alias null».

Предложение WHERE фильтрует как левую, так и правую сторону JOIN, в то время как предложение ON всегда будет фильтровать только правую сторону.

  1. Если вы всегда хотите извлекать левые строки и только JOIN, если какое-либо условие соответствует, то вы должны использовать предложение ON.
  2. Если вы хотите отфильтровать продукт соединения с обеих сторон, вы должны использовать предложение WHERE.
1

для повышения эффективности таблицы должны иметь специальную индексированную колонку для использования для JOINS.

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

, поэтому вы присоединяетесь к использованию индексированных столбцов, а затем после JOIN вы запустите условие в индексированном столбце none.

5

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

Вот пример:

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' будет иметь с собой соответствующую строку.

0

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