我运行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
我的第二个问题是:我可以以某种方式改变这种行为吗? (例如在服务器配置中?)
祝你好运, 彼得
答案 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子句过滤掉了所有行,这些行与逐行连接子句之后应用的条件不匹配。