SQL оставил соединение с фильтром в условии JOIN против фильтра в предложении WHERE - PullRequest
0 голосов
/ 11 сентября 2018

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

Запросы следующие:

select *
from TableA as a
left join TableB b on a.id = b.id and b.status in (10, 100)

select *
from TableA as a
left join TableB b on a.id = b.id
where b.status is null or b.status in (10, 100)

Когда будут этине вернуть тот же результат?

Ответы [ 7 ]

0 голосов
/ 11 сентября 2018
select * from TableA as a left join TableB b on a.id = b.id and b.status in (10, 100)

Условный оператор AND вычисляется до того, как произойдет объединение.

select * from TableA as a left join TableB b on a.id = b.id
  where b.status is null or b.status in (10, 100)

Фильтр происходит после объединения таблиц.

ТАК, по этой причине вы получите другоевыход.

0 голосов
/ 11 сентября 2018

Поскольку это LEFT JOIN, несоответствующее условие ON будет просто генерировать значения NULL для столбцов из правой таблицы .

С другой стороны, несоответствующее предложение WHERE будет полностью исключать строку независимо от типа соединения . Рассмотрим этот пример:

CREATE TABLE #TableA(id INT);
INSERT INTO  #TableA VALUES
    (1),
    (2);
CREATE TABLE #TableB(id INT, status INT);
INSERT INTO  #TableB VALUES
    (1, 10),
    (2, -1);

SELECT *
FROM #TableA AS A
LEFT JOIN #TableB B ON A.id = B.id AND B.status IN (10)
/*
    a.id | b.id | status
    1    | 1    | 10
    2    | NULL | NULL
*/    

SELECT *
FROM #TableA AS A
LEFT JOIN #TableB B ON A.id = B.id
-- WHERE B.status IS NULL OR B.status IN (10)
/*
    a.id | b.id | status
    1    | 1    | 10
    2    | 2    | -1
*/

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

0 голосов
/ 11 сентября 2018

По логике говоря, ваш второй запрос почти такой же, как:

SELECT *
FROM TableA as a
LEFT JOIN TableB b
    ON a.id = b.id
WHERE b.status IN (10, 100);  -- b.status is null has been removed

Итак, проблема сводится к стандартной проблеме фильтрации в предложении ON по сравнению с фильтрацией в предложении WHERE. В первом случае все записи с левой стороны объединения будут сохранены, даже если логика ON не будет выполнена. В последнем случае, который является случаем вашего второго запроса, соответствующие записи, которые не удовлетворяют условию status, будут удалены и не будут отображаться в наборе результатов.

Я сказал почти то же самое, потому что проверка b.status IS NULL, которую вы имели, фактически позволила бы выжить записям, которые соответствовали в условии соединения, но которые, как оказалось, имели null значение для status. Но, кроме этого, ваш вопрос на самом деле является лишь вопросом фильтрации в предложении ON вместо выполнения этого в предложении WHERE.

0 голосов
/ 11 сентября 2018

Позвольте мне показать пример:

SELECT * INTO #A FROM (VALUES 
(1),(2),(3),(4)) T(id)

SELECT * INTO #B FROM (VALUES
(1,NULL),
(2,1),
(3,10)) T(id,status)

select *
from #A as a
left join #B b on a.id = b.id and b.status in (10, 100)

select *
from #A as a
left join #B b on a.id = b.id
where b.status is null or b.status in (10, 100)

Результат

id          id          status
----------- ----------- -----------
1           NULL        NULL
2           NULL        NULL
3           3           10
4           NULL        NULL

id          id          status
----------- ----------- -----------
1           1           NULL
3           3           10
4           NULL        NULL

Окончательный ответ:

  1. Если статус не в (10 100), LEFT JOIN применяет NULL
  2. Если статус равен NULL, LEFT JOIN также применяет NULL, предикат недействителен
0 голосов
/ 11 сентября 2018

В обычном сценарии A LEFT JOIN или LEFT OUTER JOIN дает все строки из левой таблицы с совпадающими строками из обеих таблиц.Когда строка в левой таблице не имеет совпадающих строк в правой таблице, соответствующая строка набора результатов содержит нулевые значения для всех столбцов списка выбора, приходящих из правой таблицы.

Когда мы добавляем предложение where с левойвнешнее соединение, оно ведет себя как внутреннее соединение, где фильтр применяется после предложения ON, показывая только те строки, которые имеют

B.status is null or 10 or 100

0 голосов
/ 11 сентября 2018

Большая разница с условием Где b.status is null or b.status in (10, 100) заключается в том, что b.status, скажем, 1, а также b.id = a.id

В первом запросе вы все равно получите строку из таблицы Aс соответствующей B-частью как NULL как On условие не полностью выполнено.Во втором запросе вы получите строку в JOIN для таблиц a и b, которая будет потеряна в предложении where.

0 голосов
/ 11 сентября 2018

В первом запросе вы получите все строки левой таблицы

Но

В секунду, где, когда вы фильтруете по параметру where cluase, он выдаст только те записи, которые полностью заполняют условие where

...