SQL-соединение: где предложение по сравнению с предложением - PullRequest
585 голосов
/ 09 декабря 2008

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


Какая разница и что должно быть в каждом?

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

Ответы [ 17 ]

1 голос
/ 13 декабря 2014

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

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

поэтому вы ПРИСОЕДИНЯЕТЕСЬ, используя индексированные столбцы, затем после СОЕДИНЕНИЯ запускаете условие для неиндексированного столбца.

1 голос
/ 30 апреля 2019

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

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

  • объединить данные в ON
  • фильтрация данных в ГДЕ

Может быть очень сложно прочитать запрос, в котором в условии WHERE существуют условие JOIN и условие фильтрации.

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

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

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

1 голос
/ 05 февраля 2014

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

Например: - «ГДЕ»

SELECT * FROM employee WHERE employee_id=101

Например: - «ВКЛ»

Есть две таблицы employee и employee_details, соответствующие столбцы - employee_id.

SELECT * FROM employee 
INNER JOIN employee_details 
ON employee.employee_id = employee_details.employee_id

Надеюсь, я ответил на ваш вопрос. Возврат для любых разъяснений.

1 голос
/ 16 февраля 2018

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

0 голосов
/ 12 апреля 2019

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

A

id | SomeData

B

id | id_A | SomeOtherData

id_A является внешним ключом таблицы A

Написание запроса:

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

Предоставит такой результат:

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

То, что находится в A, но не в B, означает, что для B есть нулевые значения.


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

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

Написание запроса:

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

0 голосов
/ 09 апреля 2019

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

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

Объединения - это не предложение оператора select, а оператор внутри 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

Короче

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

0 голосов
/ 26 апреля 2010

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

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

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

...