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