T - SQL-Left Outer Joins-фильтры в предложении where против предложения on
я пытаюсь сравнить две таблицы, чтобы найти строки в каждой таблице, что нет в других. В таблице 1 есть столбец groupby для создания 2 наборов данных в таблице one.
groupby number
----------- -----------
1 1
1 2
2 1
2 2
2 4
Таблица 2 имеет только один столбец.
number
-----------
1
3
4
таким образом, Таблица 1 имеет значения 1,2,4 в группе 2, а Таблица 2 имеет значения 1,3,4.
я ожидаю следующий результат при присоединении к группе 2:
`Table 1 LEFT OUTER Join Table 2`
T1_Groupby T1_Number T2_Number
----------- ----------- -----------
2 2 NULL
`Table 2 LEFT OUTER Join Table 1`
T1_Groupby T1_Number T2_Number
----------- ----------- -----------
NULL NULL 3
единственный способ заставить это работать, если я поставлю где предложение для первого соединения:
PRINT 'Table 1 LEFT OUTER Join Table 2, with WHERE clause'
select table1.groupby as [T1_Groupby],
table1.number as [T1_Number],
table2.number as [T2_Number]
from table1
LEFT OUTER join table2
--******************************
on table1.number = table2.number
--******************************
WHERE table1.groupby = 2
AND table2.number IS NULL
и фильтр в ON для второго:
PRINT 'Table 2 LEFT OUTER Join Table 1, with ON clause'
select table1.groupby as [T1_Groupby],
table1.number as [T1_Number],
table2.number as [T2_Number]
from table2
LEFT OUTER join table1
--******************************
on table2.number = table1.number
AND table1.groupby = 2
--******************************
WHERE table1.number IS NULL
может ли кто-нибудь придумать способ не использовать фильтр в предложении on, но в предложении where?
контекст этого-у меня есть промежуточная область в базе данных, и я хочу определить новые записи и записи, которые были удалены. Поле groupby является эквивалентом batchid для извлечения, и я сравниваю последний экстракт в таблице temp с партия со вчерашнего дня хранится в таблице partioneds, в которой также есть все ранее извлеченные партии. Код для создания таблиц 1 и 2:
create table table1 (number int, groupby int)
create table table2 (number int)
insert into table1 (number, groupby) values (1, 1)
insert into table1 (number, groupby) values (2, 1)
insert into table1 (number, groupby) values (1, 2)
insert into table2 (number) values (1)
insert into table1 (number, groupby) values (2, 2)
insert into table2 (number) values (3)
insert into table1 (number, groupby) values (4, 2)
insert into table2 (number) values (4)
EDIT:
немного больше контекста-в зависимости от того, где я поставил фильтр I разные результаты. Как указано выше предложении where дает мне правильный результат в одном государстве и в другом. Я ищу последовательный способ сделать это.
где -
select table1.groupby as [T1_Groupby],
table1.number as [T1_Number],
table2.number as [T2_Number]
from table1
LEFT OUTER join table2
--******************************
on table1.number = table2.number
--******************************
WHERE table1.groupby = 2
AND table2.number IS NULL
результат:
T1_Groupby T1_Number T2_Number
----------- ----------- -----------
2 2 NULL
On -
select table1.groupby as [T1_Groupby],
table1.number as [T1_Number],
table2.number as [T2_Number]
from table1
LEFT OUTER join table2
--******************************
on table1.number = table2.number
AND table1.groupby = 2
--******************************
WHERE table2.number IS NULL
результат:
T1_Groupby T1_Number T2_Number
----------- ----------- -----------
1 1 NULL
2 2 NULL
1 2 NULL
где (Таблица 2 на этот раз) -
select table1.groupby as [T1_Groupby],
table1.number as [T1_Number],
table2.number as [T2_Number]
from table2
LEFT OUTER join table1
--******************************
on table2.number = table1.number
AND table1.groupby = 2
--******************************
WHERE table1.number IS NULL
результат:
T1_Groupby T1_Number T2_Number
----------- ----------- -----------
NULL NULL 3
On -
select table1.groupby as [T1_Groupby],
table1.number as [T1_Number],
table2.number as [T2_Number]
from table2
LEFT OUTER join table1
--******************************
on table2.number = table1.number
--******************************
WHERE table1.number IS NULL
AND table1.groupby = 2
результат:
T1_Groupby T1_Number T2_Number
----------- ----------- -----------
(0) rows returned
6 ответов
Если вы фильтруете левую внешнюю присоединенную таблицу в предложении WHERE, то вы фактически создаете внутреннее соединение
Смотрите также эту страницу wiki:где условия слева присоединиться
с левыми внешними соединениями вы должны отфильтровать предложение ON или использовать это:
WHERE
(LeftJoinTable.ID IS NULL OR LeftJoinTable.Col1=YourFilter)
Если вы просто фильтруете в WHERE:
WHERE
LeftJoinTable.Col1=YourFilter
вы отбросите родительскую строку присоединения всякий раз, когда нет LeftJoinTable.ID (делает соединение внутренним соединением).
помещая фильтр в ON, вы вызываете исключение левой строки соединения, но не исключение родительской строки соединения, Вот как это работает.
редактировать комментарий базы don OP
единственный способ фильтровать левую внешнюю таблицу соединений - в предложении ON, если вы не хотите использовать или как я показываю в первом примере кода выше. Нет ничего плохого в фильтрации левого внешнего соединения в предложении ON, вот как вы это делаете.
по мере написания запроса имеет смысл поместить join в предложение ON, так как вы специально хотите присоединиться только к значениям в группе " 2 " из таблицы 1.
альтернативой является prefilter table1 для группы, которая вас интересует, например
select t1Group.groupby,
t1Group.number as [T1_Number],
table2.number as [T2_Number]
from table2
LEFT OUTER join (SELECT * FROM table1 WHERE groupby=2) t1Group
on table2.number = t1Group.number
WHERE t1Group.number IS NULL
SELECT dbo.table1.groupby as [T1_Groupby],
dbo.table1.number as [T1_Number],
t21.number as [t21_Number]
FROM dbo.table1
LEFT OUTER join dbo.table2 t21
ON dbo.table1.number = t21.number
LEFT OUTER join dbo.table2 t22
ON dbo.table1.groupby= t22.number
WHERE t21.number is null AND t22.number is null
select dbo.table1.groupby as [T1_Groupby],
dbo.table1.number as [T1_Number],
t22.number as [t22_Number]
from dbo.table1 right outer join
(select dbo.table1.groupby,
dbo.table2.number as number
from dbo.table1
right OUTER join dbo.table2
on dbo.table1.number = dbo.table2.number
where dbo.table1.number is null) t22
on dbo.table1.groupby = t22.number
where dbo.table1.groupby is null
Я сам боролся с этим - и в конце дня должен был выбрать данные из таблицы с предложением Where и поместить его во временную таблицу, а затем использовать левое внешнее соединение на временной таблице.
SELECT table1.GroupBy, table1.number INTO #Temp FROM table1 WHere GroupBy = 2
SELECT table2.Groupby, #temp.number From table2 LEFT OUTER JOIN #temp on table2.Groupby = #temp.Groupby