【问题标题】:Difference between "and" and "where" in joins连接中“and”和“where”的区别
【发布时间】:2010-04-01 08:52:56
【问题描述】:

有什么区别

SELECT DISTINCT field1 
  FROM table1 cd  
  JOIN table2 
    ON     cd.Company = table2.Name 
       and table2.Id IN (2728) 

SELECT DISTINCT field1 
  FROM table1 cd  
  JOIN table2 
    ON cd.Company = table2.Name 
 where table2.Id IN (2728) 

两者都返回相同的结果并且具有相同的解释输出

【问题讨论】:

  • 小提示:看一下执行计划,可能会提供更多见解。 SQL 做了很多查询优化。

标签: sql join


【解决方案1】:

首先存在语义差异。当你有一个连接时,你说的是两个表之间的关系是由那个条件定义的。所以在你的第一个例子中,你说这些表是由cd.Company = table2.Name AND table2.Id IN (2728) 关联的。当您使用 WHERE 子句时,您是说该关系由 cd.Company = table2.Name 定义,并且您只想要条件 table2.Id IN (2728) 适用的行。尽管这些给出了相同的答案,但对于阅读您的代码的程序员来说,这意味着非常不同的事情。

在这种情况下,WHERE 子句几乎肯定就是您的意思,因此您应该使用它。

其次,在您使用 LEFT JOIN 而不是 INNER JOIN 的情况下,结果实际上存在差异。如果您将第二个条件作为连接的一部分,那么如果条件失败,您仍然会得到一个结果行——您将从左表中获取值,而右表则为空值。如果您将条件作为 WHERE 子句的一部分包含在内,并且该条件失败,您将根本无法获得该行。

这里有一个例子来证明这一点。

查询 1(在哪里):

SELECT DISTINCT field1
  FROM table1 cd
  LEFT JOIN table2
    ON cd.Company = table2.Name
 WHERE table2.Id IN (2728);

结果:

field1
200

查询 2 (AND):

SELECT DISTINCT field1
  FROM table1 cd
  LEFT JOIN table2
    ON cd.Company = table2.Name
   AND table2.Id IN (2728);

结果:

field1
100
200

使用的测试数据:

CREATE TABLE table1 (Company NVARCHAR(100) NOT NULL, Field1 INT NOT NULL);
INSERT INTO table1 (Company, Field1) VALUES
('FooSoft', 100),
('BarSoft', 200);

CREATE TABLE table2 (Id INT NOT NULL, Name NVARCHAR(100) NOT NULL);
INSERT INTO table2 (Id, Name) VALUES
(2727, 'FooSoft'),
(2728, 'BarSoft');

【讨论】:

  • +1 用于提及 LEFT JOIN。仍然我会无耻地指出我的答案stackoverflow.com/questions/2559194/… 可能更多的细节和原因:)
  • 在您的示例中(使用 AND 查询 2)如果我们有 table1.Id IN (100);它仍然会返回两行..这是为什么?...
  • @psj01,这是因为 table1 在该查询中被左连接,所以 table1 的所有行都将包含在结果集中,而与左连接条件无关。
【解决方案2】:

SQL 来自relational algebra

查看差异的一种方法是,JOIN 是对集合的操作,可以在结果中产生比原始表中更多或更少的记录。另一方面,WHERE 将始终限制结果的数量。

剩下的文字是额外的解释。


有关连接类型的概述,请再次参阅article

当我说 where 条件将始终限制结果时,您必须考虑到,当我们谈论对两个(或更多)表的查询时,您必须以某种方式将这些表中的记录配对,即使没有JOIN 关键字。

因此,在 SQL 中,如果表只是用逗号分隔,您实际上是在使用 CROSS JOIN(笛卡尔积),它返回一个表中的每一行对应另一个表中的每一行。

由于这是两个表中行组合的最大数量,因此交叉连接表上的任何 WHERE 的结果都可以表示为 JOIN 操作。

但请记住,当您引入 LEFT、RIGHT 和 FULL OUTER 联接时,此最大值存在例外情况。

LEFT JOIN 将在给定条件下将左表中的记录与右表中的记录连接起来,但是如果连接条件,则查看左表中的一行对于右表中的任何记录都不满足 LEFT JOIN仍然会从左表返回一条记录,而在来自右表的列中,它将返回 NULL(RIGHT JOIN 的工作方式类似,但另一方面,FULL OUTER 同时工作)。

由于默认的交叉连接不返回那些记录,你不能用 WHERE 条件表达这些连接条件,你不得不使用 JOIN 语法(oracle 是一个例外,它扩展了 SQL 标准和 = 运算符,但是这未被其他供应商或标准所接受)。

此外,连接通常(但并非总是)与现有的参照完整性相一致,并建议实体之间的关系,但我不会对此给予太多重视,因为 where 条件可以做同样的事情(除了前面提到的情况)和对于一个好的 RDBMS 来说,指定标准的地方并没有什么不同。

【讨论】:

    【解决方案3】:
    • join用于反映实体关系
    • where 子句过滤掉结果。

    所以连接子句是“静态的”(除非实体关系发生变化),
    而 where 子句是特定于用例的。

    【讨论】:

      【解决方案4】:

      没有区别。 “ON”就像“WHERE”的同义词,所以第二种读法如下:

      JOIN table2 WHERE cd.Company = table2.Name AND table2.Id IN (2728)

      【讨论】:

      【解决方案5】:

      查询优化引擎将其分解为相关的查询运算符时没有区别。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-06-19
        • 2012-10-19
        • 2015-04-22
        • 2023-02-25
        • 1970-01-01
        • 2014-05-17
        • 2011-05-05
        • 2012-05-25
        相关资源
        最近更新 更多