【问题标题】:SQL Server : query with multiple LEFT OUTER JOIN and WHERE conditionsSQL Server:使用多个 LEFT OUTER JOIN 和 WHERE 条件进行查询
【发布时间】:2013-11-22 12:31:47
【问题描述】:

我运行 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'

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

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

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

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

最好的问候, 彼得

【问题讨论】:

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


    【解决方案1】:

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

    第二:我希望不会!修正您的查询!

    【讨论】:

    • 感谢您指出这一点 - 我会检查是否是这种情况(ANSI NULLS)。需要明确的是:我不会破坏这种逻辑——我想理解它。正如我所说的 ANSI NULLS 可能会影响 MSSQL 2005 - Oracle Server 怎么样,我也试过了。
    • “它们是不同的,外部连接表中的列上的表达式在 ON 子句之外毫无意义”正是我所追求的。谢谢,这刚刚解决了我的问题查询。
    【解决方案2】:

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

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

    【讨论】:

    • 我完全理解 WHERE 的工作原理——我的困惑可能来自我以某种方式将别名创建与 ON 子句执行联系起来。现在开始对我来说很明显了。感谢您花时间回答我的问题!
    【解决方案3】:
    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 之前应用,从而可以正确过滤结果行。

    【讨论】:

      【解决方案4】:

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

      对于左外连接,对于相同的条件,根据放置的位置(连接子句或 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
      

      这里,驱动表的列被保留,但连接子句使从表中不匹配的行为空。

      WHERE 子句中的条件

      对于WHERE子句中的条件:

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

      这给出了:

      2   2
      

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-01-10
        • 2010-09-29
        • 2011-06-12
        • 1970-01-01
        • 2014-08-10
        相关资源
        最近更新 更多