T-SQL - 左外连接 - where 子句与 on 子句中的过滤器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2930033/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-01 06:23:14  来源:igfitidea点击:

T-SQL - Left Outer Joins - Filters in the where clause versus the on clause

sqlleft-join

提问by Greg Potter

I am trying to compare two tables to find rows in each table that is not in the other. Table 1 has a groupby column to create 2 sets of data within table one.

我试图比较两个表以在每个表中查找不在另一个表中的行。表 1 有一个 groupby 列,用于在表一中创建 2 组数据。

groupby     number
----------- -----------
1           1
1           2
2           1
2           2
2           4

Table 2 has only one column.

表 2 只有一列。

number
-----------
1
3
4

So Table 1 has the values 1,2,4 in group 2 and Table 2 has the values 1,3,4.

因此,表 1 在组 2 中具有值 1、2、4,而表 2 具有值 1、3、4。

I expect the following result when joining for Group 2:

加入第 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

The only way I can get this to work is if I put a where clause for the first join:

我可以让它工作的唯一方法是如果我为第一次加入放置一个 where 子句:

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

and a filter in the ON for the second:

和第二个 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

Can anyone come up with a way of not using the filter in the on clause but in the where clause?

谁能想出一种不在 on 子句中而是在 where 子句中使用过滤器的方法?

The context of this is I have a staging area in a database and I want to identify new records and records that have been deleted. The groupby field is the equivalent of a batchid for an extract and I am comparing the latest extract in a temp table to a the batch from yesterday stored in a partioneds table, which also has all the previously extracted batches as well. Code to create table 1 and 2:

上下文是我在数据库中有一个暂存区,我想识别新记录和已删除的记录。groupby 字段相当于提取的 batchid,我将临时表中的最新提取与昨天存储在分区表中的批次进行比较,该表也包含所有先前提取的批次。创建表 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:

编辑:

A bit more context - depending on where I put the filter I different results. As stated above the where clause gives me the correct result in one state and the ON in the other. I am looking for a consistent way of doing this.

更多的上下文 - 根据我放置过滤器的位置,我会得到不同的结果。如上所述,where 子句在一种状态下给出了正确的结果,而在另一种状态下给出了 ON。我正在寻找一种一致的方式来做到这一点。

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

Result:

结果:

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

Result:

结果:

T1_Groupby  T1_Number   T2_Number
----------- ----------- -----------
1           1           NULL
2           2           NULL
1           2           NULL

Where (table 2 this time) -

哪里(这次是表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

Result:

结果:

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

Result:

结果:

T1_Groupby  T1_Number   T2_Number
----------- ----------- -----------
(0) rows returned

回答by SQLMenace

If you filter the left outer joined table in the WHERE clause then you are in effect creating an inner join

如果您在 WHERE 子句中过滤左外连接表,那么您实际上是在创建内连接

See also this wiki page: WHERE conditions on a LEFT JOIN

另请参阅此 wiki 页面:LEFT JOIN 上的 WHERE 条件

回答by KM.

with LEFT OUTER JOINS, you must filter in the ON clause or use this:

使用 LEFT OUTER JOINS,您必须在 ON 子句中进行过滤或使用:

WHERE
    (LeftJoinTable.ID IS NULL OR LeftJoinTable.Col1=YourFilter)

if you just filter in the WHERE:

如果你只是在 WHERE 中过滤:

WHERE 
    LeftJoinTable.Col1=YourFilter

you will discard the parent joining row whenever there isn't a LeftJoinTable.ID (making the join an INNER JOIN).

只要没有 LeftJoinTable.ID(使连接成为 INNER JOIN),您就会丢弃父连接行。

By placing the filter in the ON, you cause the elimination of the LEFT JOIN row but not the elimination of the parent joining row, that is just how it works.

通过将过滤器置于 ON 中,您会消除 LEFT JOIN 行,但不会消除父连接行,这就是它的工作原理。

EDITbase don OP's comment
the only way to filter a a LEFT OUTER JOIN table is in the ON clause, unless you want to use an OR like I show in the first code example above. There is nothing wrong filtering a LEFT OUTER JOIN in the ON clause, this is how you do it.

EDITbase don OP's comment
过滤 LEFT OUTER JOIN 表的唯一方法是在 ON 子句中,除非您想使用我在上面第一个代码示例中显示的 OR。在 ON 子句中过滤 LEFT OUTER JOIN 没有任何错误,这就是您的做法。

回答by mdma

As the query is written, it makes sense to put the join in the ON clause, since you specifically only want to join on values in group '2' from table 1.

在编写查询时,将联接放在 ON 子句中是有意义的,因为您特别只想联接表 1 中组“2”中的值。

The alternative is to prefilter table1 to the group you are interested in, like this

另一种方法是将 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

回答by angel

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

回答by angel

    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

回答by KMW

I have been struggling with this myself - and at the end of the day was to select data from table with Where Clause and put it into a temp table, and then use Left outer join on the Temp Table.

我自己一直在努力解决这个问题 - 最后是从带有 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