【问题标题】:SQL INNER JOIN vs LEFT JOIN with a WHERESQL INNER JOIN vs LEFT JOIN with a WHERE
【发布时间】:2016-04-28 06:10:55
【问题描述】:

我正在尝试更直观地掌握 SQL 连接。就在昨天,我了解到如何将 RIGHT JOIN 重写为 LEFT JOIN(通过翻转表的顺序),这有助于我更好地理解这两个连接的工作方式。

但是,现在我想知道是否可以将 INNER JOIN 重写为带有 WHERE 条件的 LEFT JOIN——这意味着它们的逻辑可能是等价的(“逻辑”不是指执行计划,而是描述预期结果集的方式)。

喜欢:

SELECT * FROM HeaderTable
INNER JOIN DetailTable 
ON HeaderTable.ID = DetailTable.ParentID

我会读作“向我显示表 HeaderTableDetailTable 中在 HeaderTable.ID 中具有匹配值的所有记录和 DetailTable.ParentID 字段。”等同于:

SELECT * FROM HeaderTable
LEFT JOIN DetailTable 
ON    HeaderTable.ID = DetailTable.ParentID
WHERE HeaderTable.ID = DetailTable.ParentID

我会读为“向我显示表 HeaderTableDetailTable 中的所有记录,其中 HeaderTable.ID 的值相同作为 DetailTable.ParentID 的值。"

这些会返回相同的结果集吗?我更多地询问逻辑是否相同,而不是一个比另一个更有效。

如果我可以问,请不要用任何维恩图来回答,因为这些似乎并不能准确地向我描述连接的逻辑。

【问题讨论】:

  • 视觉表示怎么能帮不上忙?是的,在您的示例中它们是相同的,因为当您在 where 子句中添加谓词时,您只会返回在两个表中都匹配的那些行。
  • 你也可以有“WHERE DetailTable.ParentID IS NOT NULL”,它会是一样的。
  • 没有数据不重复。当第二个表中有多行与连接谓词匹配时,会发生什么情况,第一个表中的值出现在两行上,因为这是放在这些行中的唯一合乎逻辑的东西。在您真正理解之前,它有点令人困惑。
  • @SeanLange 说得有道理,但我不认为这与维恩图所显示的完全一样,IMO。并且“第一个表中的值出现在两行上”,这就是我所说的重复数据的意思——这很好而且有用,我只是不认为维恩特别传达了这种可能性。只是我的一个非常挑剔的意见,但仍然只是一个意见
  • 现在您已经了解了它的工作原理,再次查看维恩图。如果你想出一个更好的描述连接的可视化工具,我当然会很感兴趣。

标签: sql-server join left-join inner-join


【解决方案1】:

是的,它们将返回相同的结果。没有 where 子句的左连接将读取为 向我显示标题表中的所有记录和详细信息表中的相关项目,或者对于没有匹配项的详细信息为 null

添加与 id 相关的 where 子句通过消除在详细信息部分显示为 null 的不匹配行,有效地将左连接转换为内连接。

在某些数据库中,例如 MS SQL Server,左连接会在查询执行计划中显示为内连接。

虽然你说你不想要维恩图,但我还是忍不住将你推荐给 this question and its answers,即使它们充满了(我认为非常有用的)维恩图。

【讨论】:

  • 我刚刚进行了一些测试,比较了 SQL Server 中的两种方法和左连接,其中在查询计划中显示为左外连接。
  • @JeffreyVanLaethem 很有趣。它正确地转换为我的 MSSQL 2012 实例中的内部联接。你运行的是什么版本?请参阅此图片作为示例:ibin.co/2UG1rsiYGfDR
  • 嗯。我的猜测是它会根据很多事情而有所不同。这太可怕了,因为现在我需要知道为什么 >_
  • @JeffreyVanLaethem - 你为什么要做WHERE IS NULL?这根本不是问题?这将执行反半联接。喜欢NOT EXISTS
  • @elmer007 是的,那是真的。问题中提出的两个查询永远不应该返回不同的结果——它们是等价的(结果,可能不是它们的执行方式——这取决于查询解析器/优化器)。
【解决方案2】:

是的,它们会返回相同的结果。

但是你可以简单地写

SELECT * 
FROM HeaderTable, DetailTable
WHERE HeaderTable.ID = DetailTable.ParentID

这也会返回相同的结果。这是在引入连接子句之前使用的旧语法。

【讨论】:

    【解决方案3】:

    在左连接中,如果您在 where 中引用左,则否定左并将其变为常规连接

    【讨论】:

    猜你喜欢
    • 2016-10-31
    • 2021-11-29
    • 2016-11-30
    • 1970-01-01
    • 2015-11-29
    • 1970-01-01
    • 2015-01-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多