Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/86.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
T-SQL-左外部联接-where子句中的过滤器与on子句中的过滤器_Sql_Left Join - Fatal编程技术网

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

T-SQL-左外部联接-where子句中的过滤器与on子句中的过滤器,sql,left-join,Sql,Left Join,我试图比较两个表,以查找每个表中不在另一个表中的行。表1有一个groupby列,用于在表1中创建两组数据 groupby number ----------- ----------- 1 1 1 2 2 1 2 2 2 4 表2只有一列 number ----------- 1 3 4 因此,表1的值为第2组中的1,2,4,表2的值为1,3,4 当我加入第2组时,我期望得到以下结果:

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

groupby     number
----------- -----------
1           1
1           2
2           1
2           2
2           4
表2只有一列

number
-----------
1
3
4
因此,表1的值为第2组中的1,2,4,表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
我能让它工作的唯一方法是,如果我为第一个连接放置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
在第二个屏幕上显示一个过滤器:

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,我将临时表中的最新提取与partioneds表中存储的昨天的批次进行比较,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)  
编辑:

更多的上下文-根据我放置过滤器的位置,我会得到不同的结果。如上所述,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
T1_Groupby  T1_Number   T2_Number
----------- ----------- -----------
1           1           NULL
2           2           NULL
1           2           NULL
T1_Groupby  T1_Number   T2_Number
----------- ----------- -----------
NULL        NULL        3
T1_Groupby  T1_Number   T2_Number
----------- ----------- -----------
(0) rows returned
在-

结果:

T1_Groupby  T1_Number   T2_Number
----------- ----------- -----------
2           2           NULL
T1_Groupby  T1_Number   T2_Number
----------- ----------- -----------
1           1           NULL
2           2           NULL
1           2           NULL
T1_Groupby  T1_Number   T2_Number
----------- ----------- -----------
NULL        NULL        3
T1_Groupby  T1_Number   T2_Number
----------- ----------- -----------
(0) rows returned
其中(本次表2)——

结果:

T1_Groupby  T1_Number   T2_Number
----------- ----------- -----------
2           2           NULL
T1_Groupby  T1_Number   T2_Number
----------- ----------- -----------
1           1           NULL
2           2           NULL
1           2           NULL
T1_Groupby  T1_Number   T2_Number
----------- ----------- -----------
NULL        NULL        3
T1_Groupby  T1_Number   T2_Number
----------- ----------- -----------
(0) rows returned
关于-

结果:

T1_Groupby  T1_Number   T2_Number
----------- ----------- -----------
2           2           NULL
T1_Groupby  T1_Number   T2_Number
----------- ----------- -----------
1           1           NULL
2           2           NULL
1           2           NULL
T1_Groupby  T1_Number   T2_Number
----------- ----------- -----------
NULL        NULL        3
T1_Groupby  T1_Number   T2_Number
----------- ----------- -----------
(0) rows returned

对于左外部联接,必须在ON子句中进行筛选或使用:

WHERE
    (LeftJoinTable.ID IS NULL OR LeftJoinTable.Col1=YourFilter)
如果您只是在其中进行筛选:

WHERE 
    LeftJoinTable.Col1=YourFilter
只要没有LeftJoinTable.ID(使联接成为内部联接),就将放弃父联接行

通过将过滤器放置在打开位置,可以消除左连接行,但不会消除父连接行,这就是它的工作方式

编辑不要发表评论

过滤左外部联接表的唯一方法是在ON子句中,除非您想使用或类似于我在上面的第一个代码示例中显示的。在ON子句中过滤左外部联接没有什么错误,这就是您的操作方式。

如果在WHERE子句中过滤左外部联接表,则实际上是在创建内部联接


另请参见此wiki页面:

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

另一种方法是将表1预过滤到您感兴趣的组中,如下所示

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

我自己也一直在努力解决这个问题,最后我用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

顶部答案中的链接不再起作用。下面是回答这个问题的另一个例子。我已经在这里复制粘贴了该链接的主要内容(不是所有内容),这样,如果该链接也停止工作,我们就不会丢失知识

TL;DR:注意左连接,因为左连接查询可能作为左连接执行,也可能不作为左连接执行。这很奇怪,但却是真的

创建样本测试数据:(在临时表中)

如果我们希望返回表1中的所有记录,而不管表2中是否有关联的记录,并在有关联记录时显示表2中的数据,我们将编写一个左联接,如下所示:

SELECT *
  FROM @Table1 tb1
        LEFT OUTER JOIN @Table2 tb2
          ON tb1.colID = tb2.columnID;

但是,如果我们现在想在查询中添加WHERE子句,以便只从ID小于4的表2中获取数据,我们可以这样做:

请注意,我们只获取两个表中都有匹配ID的值。这看起来像一个内部联接,实际上是作为一个内部联接执行的。要确认这一点,请在运行带WHERE条件和不带WHERE条件的左连接后,查看执行计划。(如果读者想了解这一细节,请访问)

那么,我们如何才能避免这种情况呢?好的,因为您首先要做一个左连接,所以显然需要或想要返回表1中的所有记录,而不管表2中的数据是什么。如果您真的不想返回表2中某些记录的数据,那么可以在连接谓词中过滤掉这些记录(连接的ON部分中的“搜索条件”)。例如,最后一个查询的编写方式如下:

SELECT *
  FROM @Table1 tb1
        LEFT OUTER JOIN @Table2 tb2
          ON tb1.colID = tb2.columnID
         AND tb2.columnID < 4;
选择*
来自@Table1 tb1
表2 tb2的左侧外部连接
在tb1.colID=tb2.columnID上
tb2.columnID<4;

请注意,我们仍然可以从表1中获得5条记录,但不能从表2中获得不符合我们标准的数据。它只为该表中不符合条件的数据返回null。我们可以再次查看执行计划,以证明我们实际上使用的是左连接。(如果读者想了解这一细节,请访问)

更多注意事项: 当有人使用IS NULL条件而不是值时,会怎么样?那么,在这种情况下,你可以在WHERE子句中使用它

如果我们使用的是notnull呢?它将进行内部连接,就像它与实际值进行连接一样


我们可以通过查看中提到的执行计划来验证上述声明。

为什么将条件从
JOIN
子句移动到
WHERE
子句很重要?当需要这种行为时,将谓词放入
连接中是一件正常的事情。将其移动到where子句并不像第一次将表1连接到表2的连接中,如果将过滤器放入on而不是where中,则会得到不同的结果这样重要。打印“Table 1 LEFT OUTER Join Table 2,使用WHERE子句”选择table1.groupby作为[T1_groupby],table1.number作为[T1_number],table2.number作为[T2_number],从table1 LEFT OUTER Join table2中选择table1.groupby作为[T2_number]——在table1.number=table2.number和table1.groupby=2上选择****************-