Разница между фильтрацией запросов в JOIN и где?

в SQL я пытаюсь фильтровать результаты на основе идентификатора и задаюсь вопросом, есть ли какая-либо логическая разница между

SELECT value 
FROM table1 
JOIN table2 ON table1.id = table2.id 
WHERE table1.id = 1

и

SELECT value 
FROM table1 
JOIN table2 ON table1.id = table2.id AND table1.id = 1

мне кажется, что логика отличается, хотя вы всегда будете получать один и тот же набор результатов, но мне было интересно, есть ли какие-либо условия, при которых вы получите два разных результирующих набора (или они всегда будут возвращать одинаковые два результирующих набора)

3 ответов


ответ нет разница, но:

Я всегда предпочитаю делать следующее.

  • всегда Присоединиться К Условиям на ON п.
  • всегда ставить фильтр на where п.

это делает запрос более читабельный.

поэтому я буду использовать этот запрос:

SELECT value
FROM table1
INNER JOIN table2
        ON table1.id = table2.id
WHERE table1.id = 1

однако, когда вы используете OUTER JOIN'S есть большая разница в сохранении фильтра в ON условие и Where состояние.

Логическая Обработка Запросов

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

(5) SELECT (5-2) DISTINCT (5-3) TOP(<top_specification>) (5-1) <select_list>
(1) FROM (1-J) <left_table> <join_type> JOIN <right_table> ON <on_predicate>
| (1-A) <left_table> <apply_type> APPLY <right_table_expression> AS <alias>
| (1-P) <left_table> PIVOT(<pivot_specification>) AS <alias>
| (1-U) <left_table> UNPIVOT(<unpivot_specification>) AS <alias>
(2) WHERE <where_predicate>
(3) GROUP BY <group_by_specification>
(4) HAVING <having_predicate>
(6) ORDER BY <order_by_list>;

схема логических запросов

Enter image description here

  • (1) от: от фаза определяет исходные таблицы запроса и обрабатывает табличные операторы. Каждый оператор таблицы применяет ряд суб этапов. Например, фазы, участвующие в соединении, являются (1-J1) Декартовое произведение, (1-J2) на фильтре, (1-J3) добавить внешние строки. От фаза генерирует виртуальную таблицу VT1.

  • (1-J1) Декартовое произведение: эта фаза выполняет Декартовое произведение (перекрестное соединение) между двумя таблицами, участвующими в операторе таблицы, генерирующий ВТ1-разъема j1.

  • (1-J2) фильтр: эта фаза фильтрует строки из VT1-J1 на основе предикат, который появляется в предложении ON (). Только строки, для которых предикат принимает значение TRUE, вставляются в ВТ1-J2 для.
  • (1-J3) Добавить Внешние Строки: если указано внешнее соединение (в отличие от CROSS JOIN или INNER JOIN), строки из сохраненной таблицы или таблиц для которых совпадение не найдено, добавляются строки из VT1-J2 как внешний строк, создавая ВТ1-Ж3.
  • (2) здесь: эта фаза фильтрует строки из VT1 на основе предикат, который появляется в предложении WHERE (). Только строки, для которых предикат принимает значение TRUE, вставляются в VT2.
  • (3) GROUP BY: этот этап упорядочивает строки из VT2 в группах на основе в списке столбцов, указанном в предложении GROUP BY, генерируется VT3. В конечном счете, в каждой группе будет одна строка результатов.
  • (4) иметь: фильтры этого участка группы из VT3 на основе предикат, который появляется в предложении HAVING (). Вставляются только группы, для которых предикат принимает значение TRUE на VT4 по.
  • (5) SELECT: эта фаза обрабатывает элементы в предложении SELECT, производя ВТ5.
  • (5-1) оценка выражений: этот этап оценивает выражения в список выбора, генерирующий VT5-1.
  • (5-2) DISTINCT: эта фаза удаляет повторяющиеся строки из VT5-1, генерирующий ВТ5-2.
  • (5-3) верх: эта фаза фильтрует указанное верхнее число или процент строк из VT5-2 на основе логического порядка, определенного порядком П., создавая таблицы ВТ5-3.
  • (6) заказ мимо: этот участок сортирует строки от VT5-3 согласно список столбцов, указанный в предложении ORDER BY, генерирующем курсор Из vc6.

это ссылка это отличная ссылка.


в то время как нет никакой разницы при использовании ВНУТРЕННИЕ СОЕДИНЕНИЯ, как отметил VR46, существует значительная разница при использовании ВНЕШНИЕ СОЕДИНЕНИЯ и оценка значения во второй таблице (для левых соединений - первая таблица для правых соединений). Рассмотрим следующую настройку:

DECLARE @Table1 TABLE ([ID] int)
DECLARE @Table2 TABLE ([Table1ID] int, [Value] varchar(50))

INSERT INTO @Table1
VALUES
(1),
(2),
(3)

INSERT INTO @Table2
VALUES
(1, 'test'),
(1, 'hello'),
(2, 'goodbye')

если мы выберем из него с помощью левого внешнего соединения и поставим условие в предложении where:

SELECT * FROM @Table1 T1
LEFT OUTER JOIN @Table2 T2
    ON T1.ID = T2.Table1ID
WHERE T2.Table1ID = 1

мы получаем следующее результаты:

ID          Table1ID    Value
----------- ----------- --------------------------------------------------
1           1           test
1           1           hello

это потому, что предложение where ограничивает результирующий набор, поэтому мы включаем только записи из таблицы 1, которые имеют идентификатор 1. Однако, если мы переместим условие в предложение on:

SELECT * FROM @Table1 T1
LEFT OUTER JOIN @Table2 T2
    ON T1.ID = T2.Table1ID
    AND T2.Table1ID = 1

мы получаем следующие результаты:

ID          Table1ID    Value
----------- ----------- --------------------------------------------------
1           1           test
1           1           hello
2           NULL        NULL
3           NULL        NULL

это потому, что мы больше не фильтруем результирующий набор по идентификатору таблицы 1-скорее мы фильтруем соединение. Таким образом, несмотря на то, что идентификатор table1 из 2 имеет совпадение во второй таблице, это исключено из соединения, но не из результирующего набора (отсюда значения null).

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


Я думаю, что ответ, помеченный как "правильный", не является правильным. Почему? Я пытаюсь объяснить:

У нас есть мнение

" всегда держите условия соединения в предложении ON всегда помещайте фильтр В где пункт"

и это неправильно. Если вы находитесь во внутреннем соединении, каждый раз Ставьте параметры фильтра в предложение ON, а не в where. Ты спрашиваешь почему? Попробуйте представить сложный запрос с общим количеством таблиц 10(f.e. каждая таблица имеет 10k recs) join, со сложным предложением WHERE(например, функции или вычисления). Если вы поместите критерии фильтрации в предложение ON, соединения между этими 10 таблицами не произойдет, где предложение не будет выполнено вообще. В этом случае вы не выполняете 10000^10 вычислений в предложении WHERE. Это имеет смысл, не помещая параметры фильтрации только в предложение WHERE.