【问题标题】:What is the difference in these two queries as getting two different result set?这两个查询获得两个不同的结果集有什么区别?
【发布时间】:2010-10-13 18:50:14
【问题描述】:

我得到这两个查询的不同结果集,第二个结果集似乎是正确的。这些查询有什么区别。

第二个是什么类型的内连接查询?

1)

FROM TABLE1 t1
 INNER JOIN TABLE2 t2 ON t1.Id = t2.Id
WHERE
 t1.StatusId = 12

2)

FROM TABLE1 t1
 INNER JOIN TABLE2 t2 ON t1.Id = t2.Id
 AND t1.StatusId = 12

【问题讨论】:

  • plsql 用于 oracle。我想你的意思是 tsql。
  • 每个人都想看到你的结果。您可以将它们附加到您的问题中吗?
  • 这是对您实际运行的查询的简化吗?有时,不是您认为导致问题的原因导致了问题。如果您已简化,请发布真实查询。这两个查询应该是等价的。
  • @HLGEM 如果您查看编辑历史记录,我认为代码确实出现了。 @dave - 您在发布后发现问题了吗?

标签: sql sql-server tsql sql-server-2005


【解决方案1】:

在 INNER JOIN 中执行此操作确实没有区别。

但是,当您使用 LEFT 或 RIGHT JOIN 时,确实将附加过滤器放入 JOIN 或 WHERE 子句中。

当您将过滤器放入 WHERE 子句时,SQL Server 先进行连接,然后完全过滤掉过滤器不适合的行。
--> 这将减少返回的行数

当您将过滤器放入 JOIN 时,SQL Server 在连接期间执行过滤,但仅在您放置过滤器的表上进行。
您仍然可以从其他表中获取所有行,但只有那些具有过滤器适合的过滤表中的数据。
--> 这不会减少行数,但是过滤器表中包含数据的列将在更多行中为空

很难解释...为了更清楚,这里有一个例子:

从RedFilter's answer获取样本数据:

CREATE TABLE [dbo].[t1](
    [ID] [int] NULL,
    [StatusID] [int] NULL
) ON [PRIMARY]
CREATE TABLE [dbo].[t2](
    [ID] [int] NULL
) ON [PRIMARY]
INSERT INTO t1 (ID, StatusID) VALUES (1, 10)
INSERT INTO t1 (ID, StatusID) VALUES (2, 11)
INSERT INTO t1 (ID, StatusID) VALUES (3, 12)
INSERT INTO t1 (ID, StatusID) VALUES (4, 12)
INSERT INTO t2 (ID) VALUES (1)
INSERT INTO t2 (ID) VALUES (3)
INSERT INTO t2 (ID) VALUES (5)

...并对其运行以下查询:

/* this returns four rows, but only two will have data 
from the second table in the second column */
SELECT t1.ID, t2.ID
FROM t1 
LEFT JOIN t2 ON t1.Id = t2.Id 

/* this returns only one row: the one where t2.ID = 1 */
SELECT t1.ID, t2.ID
FROM t1 
LEFT JOIN t2 ON t1.Id = t2.Id 
WHERE t2.ID = 1 

/* this returns four rows as in the first query, but only one 
row will have data in the second column: the one where t2.ID = 1 */
SELECT t1.ID, t2.ID
FROM t1 
LEFT JOIN t2 ON t1.Id = t2.Id 
AND t2.ID = 1 

注意 cmets 中显示的不同结果。

【讨论】:

    【解决方案2】:

    这些查询应该返回相同的结果。请发布完整的查询。

    下面是一个示例,展示了两种变体的相同输出:

    示例:

    CREATE TABLE [dbo].[t1](
        [ID] [int] NULL,
        [StatusID] [int] NULL
    ) ON [PRIMARY]
    CREATE TABLE [dbo].[t2](
        [ID] [int] NULL
    ) ON [PRIMARY]
    INSERT INTO t1 (ID, StatusID) VALUES (1, 10)
    INSERT INTO t1 (ID, StatusID) VALUES (2, 11)
    INSERT INTO t1 (ID, StatusID) VALUES (3, 12)
    INSERT INTO t1 (ID, StatusID) VALUES (4, 12)
    INSERT INTO t2 (ID) VALUES (1)
    INSERT INTO t2 (ID) VALUES (3)
    INSERT INTO t2 (ID) VALUES (5)
    
    SELECT t1.ID, t1.StatusID
    FROM t1 
    INNER JOIN t2 ON t1.Id = t2.Id 
    WHERE t1.StatusId = 12 
    
    SELECT t1.ID, t1.StatusID
    FROM t1 
    INNER JOIN t2 ON t1.Id = t2.Id 
        AND t1.StatusId = 12 
    

    输出:

    ID          StatusID
    ----------- -----------
    3           12
    
    (1 row(s) affected)
    
    ID          StatusID
    ----------- -----------
    3           12
    
    (1 row(s) affected)
    

    【讨论】:

    • 它们并不相同......两者之间存在细微差别
    • @Leslie:这是不正确的。对于INNER JOIN,无论是在WHERE 子句还是ON 子句中过滤,结果都是相同的。
    • 同意。差异对外部连接很重要,但对内部连接无关紧要。
    【解决方案3】:

    查看问题的编辑历史,您的查询似乎符合以下几行。

    查询一

      INNER JOIN dbo.T2
            ON ...
        LEFT OUTER  JOIN dbo.T3
            ON  ...
        WHERE 
         T3.col = somevalue AND ...
    

    查询二

      INNER JOIN dbo.T2
            ON ...
        LEFT OUTER  JOIN dbo.T3
            ON  ... AND T3.col = somevalue
       WHERE 
            ... 
    

    它们之间的区别在于查询一有效地将LEFT 连接转换为INNER 连接。

    从概念上讲,对于左外连接,会发生以下情况。

    1. T2 连接到 T3 并评估连接子句中的谓词。
    2. T2 中任何不匹配的行都将添加回 T3 列值的 NULL 值。
    3. 应用了 WHERE 子句。

    在第 2 步中重新添加的这些行都不会满足第 3 步中的 T3.col = somevalue 谓词,因为我们知道所有这些行的该列的值都是 NULL。

    【讨论】:

      【解决方案4】:

      SQL 是一种声明性语言,由 DBMS 来实现您的查询。 SQL Server 查询优化器不关心您是使用JOIN 表达式、WHERE 表达式、IN 表达式还是EXISTS 表达式对两个表进行内连接,在内部它们都被视为相同。 SQL Server 有 3 种不同的内部连接算法,它们仅根据行数和数据分布进行选择,而不是用于声明它们的确切语法。如果您比较示例中两个查询的执行计划,您应该会发现它们是相同的,因此会产生相同的结果集。

      【讨论】:

        【解决方案5】:

        底层的区别在于 WHERE 子句是在所有连接之后访问的。

        这意味着在这种情况下可能没有区别,但当有多个连接时,情况并非总是如此。在处理 WHERE 之前,可以将它们从虚拟结果集中(取决于具体情况)排除。

        请查看此链接:http://blog.sqlauthority.com/2009/04/06/sql-server-logical-query-processing-phases-order-of-statement-execution/

        【讨论】:

          【解决方案6】:

          我相信是这样的:

          第一个查询从连接的表中获取所有结果,然后过滤 WHERE 子句。

          第二个查询从表 1 中获取 StatusID = 12 的结果,然后对结果集执行联接。

          这是一个微妙的区别。

          编辑: 这是验证差异的文章的链接: http://www.sqlteam.com/article/additional-criteria-in-the-join-clause

          【讨论】:

          • 这种细微的差异如何导致输出差异?
          • 是的,但问题是他们为什么不返回相同的结果。从肉眼看来,它们请求相同的信息,我猜从它们的角度来看,它们会生成相同的执行计划。
          • -1:在这种情况下相信是不够的 - 请提供一个示例用例来证明输出的差异。
          • -1 也是如此。我测试了多个表,无论使用WHERE t1.StatusId = 12 或添加AND t1.StatusId = 12 作为连接的一部分,执行计划都是相同的。 SQL 应该足够聪明,可以根据查询找出执行计划。
          • 从您链接到的文章中:“请注意,如果我们使用内连接而不是外连接,结果集没有区别,因为内连接无论如何都会删除不匹配的记录。 "
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2010-12-19
          • 2017-04-19
          • 1970-01-01
          • 1970-01-01
          • 2013-04-11
          • 2012-04-19
          • 1970-01-01
          相关资源
          最近更新 更多