SQL Server:使用多个LEFT OUTER JOIN和WHERE条件进行查询

时间:2013-11-22 12:31:48

标签: sql-server sql-server-2008 left-join where

我运行SQL Server 2008,我正在尝试执行以下SQL查询:

查询1:

SELECT *
FROM tableA
LEFT OUTER JOIN tableB AS tabX ON tabX.some_id = tableA.some_id
LEFT OUTER JOIN tableB AS tabY ON tabY.some_id = tableA.some_id
WHERE tabX.some_attribute = 'X'
AND tabY.some_attribute = 'Y'

我已经知道WHERE语句之后的条件会导致LEFT OUTER JOIN陷入困境,并且通常会使其表现得像经典INNER JOIN。有趣的是,SQL Server 2005并非如此。

为了解决这个问题,我可以这样做:

查询2:

SELECT *
FROM tableA
LEFT OUTER JOIN tableB AS tabX ON tabX.some_id = tableA.some_id AND tabX.some_attribute = 'X'
LEFT OUTER JOIN tableB AS tabY ON tabY.some_id = tableA.some_id AND tabY.some_attribute = 'Y'

基本上我必须在WHERE语句中包含ON条件,查询将按照预期的方式执行。

我的第一个问题是:为什么SQL Server不能以相同的方式解释这两个查询(如旧的SQL Server版本或Oracle DBServer那样)?

我问,因为我对第一个查询的条件(在WHERE语句之后)如何以及为什么影响主逻辑库(我的意思是“主要结果”)感到困惑。特别是因为两个条件都特别指代别名tabX和tabY

我的第二个问题是:我可以以某种方式改变这种行为吗? (例如在服务器配置中?)

祝你好运, 彼得

4 个答案:

答案 0 :(得分:2)

第一个问题:除非您的某种ANSI NULLS开关混淆了2005 DB中的问题,否则没有数据库引擎可以解释相同的查询。它们是不同的,并且外连接表中的列上的表达式在ON子句之外是无意义的(无论您是否理解或同意它)。混淆在于你,而不是SQL Server。你在质疑的是预期的。

第二:我希望不是!修复您的疑问!

答案 1 :(得分:1)

在where语句中添加条件时,只返回与这些条件匹配的行,因此在这种情况下使用外连接可能毫无意义。这是设计的,并且在SQL2005,2008,2012中以相同的方式工作。

关于ANSI NULL:In SQL Server, what does "SET ANSI_NULLS ON" mean?

答案 2 :(得分:1)

SELECT *
FROM tableA
LEFT OUTER JOIN (SELECT * FROM tableB WHERE some_attribute = 'X') AS tabX ON tabX.some_id = tableA.some_id 
AND 
LEFT OUTER JOIN (SELECT * FROM tableB WHERE some_attribute = 'Y') AS tabY ON tabY.some_id = tableA.some_id

尝试从WHERE子句中取出条件并将它们包含在JOIN表中。这样就可以在OUTER JOIN之前应用条件,从而允许对结果行进行正确的过滤。

答案 3 :(得分:1)

左外连接 - ON子句与WHERE子句

对于左外连接,对于相同的条件,根据放置的位置 - join子句或where子句,存在很大差异。

使用MS SQL-Server:

DECLARE @t1 TABLE ( id INT )
INSERT INTO @t1 VALUES ( 1 ),( 2 ),( 3 ),( 4 ),( 5 );

DECLARE @t2 TABLE ( id INT )
INSERT INTO @t2 VALUES ( 2 ),( 3 ),( 10 ),( 11 ),( 12 );

SELECT * FROM @t1 t1
LEFT OUTER JOIN @t2 t2 ON t2.id = t1.id

这给出了:

1   NULL
2   2
3   3
4   NULL
5   NULL

正如预期的那样,来自驱动表的所有行都带有NULL,从而无法与从属表匹配。

ON子句中的条件

对于ON子句中的条件:

SELECT * FROM @t1 t1
LEFT OUTER JOIN @t2 t2 ON t2.id = t1.id AND t1.id = 2

这给出了:

1   NULL
2   2
3   NULL
4   NULL
5   NULL

这里保留了驱动表的列,但join子句使从表中的不匹配行为NULL。

WHERE子句中的条件

对于WHERE子句中的条件:

SELECT * FROM @t1 t1
LEFT OUTER JOIN @t2 t2 ON t2.id = t1.id
WHERE t1.id = 2

这给出了:

2   2

这只给出了匹配的行,因为where子句过滤掉了所有行,这些行与逐行连接子句之后应用的条件不匹配。