【问题标题】:Is it true that using INNER JOIN after any OUTER JOIN will essentially invalidate the effects of OUTER JOIN?在任何 OUTER JOIN 之后使用 INNER JOIN 是否真的会使 OUTER JOIN 的效果无效?
【发布时间】:2019-08-01 07:40:21
【问题描述】:

换句话说,对于嵌套/多个JOIN SQL 语句,是否可以肯定地说应该始终首先使用INNER JOIN(将其放在顶行或使用括号将INNER JOIN 放在前面两个表)并确保它位于任何OUTER JOINLEFTRIGHTFULL)之前?


我的理解是匹配列(例如,主键列和外键列)通常没有 NULL 值。当INNER JOIN 被另一个表编辑时,任何不匹配的行,包括来自OUTER JOIN 结果的NULL,都将被删除,因为没有任何东西可以匹配NULL!!

(顺便说一句,我从来没有使用同时具有 NULL 的列加入任何两个表,因此,我不会评论 NULL 值是否会匹配 NULL 值时 INNER JOIN-ing表。至少,我猜这将非常罕见)

【问题讨论】:

  • 长话短说,是的。只是不要这样做,睡个好觉。

标签: sql join inner-join outer-join


【解决方案1】:

从内部连接开始,然后使用left joins 是一个很好的一般规则。 right joins 几乎从未真正需要,full joins 是一个特例。这基本上就是我编写查询的方式。

但是,它确实取决于join 条件是什么。所以,虽然我认为上面的规则对于编写几乎任何查询都是合理且足够的,但是可能在外部联接之后编写内部联接的查询。

【讨论】:

  • However, it does depend on what the join conditions are... 除了比较两列的值之外,您是否还在JOIN 谓词中使用了其他类型的条件?听说在所有其他情况下最好使用WHERE
  • @尼古拉斯。 . .任何布尔条件都可以放在on 子句中,包括带有子查询的inexists。逻辑可能相当复杂。 . .虽然这种复杂性通常是不必要的。
  • "right joins are almost never really needed" > 多年来我一直在说,RIGHT JOIN 往往只是需要重构的 LEFT JOIN。
  • @Nicholas 应使用 JOIN 条件将表链接在一起,并应使用 WHERE 过滤这些 JOIN 的结果。
  • @Nicholas,如果你想过滤你离开加入的内容(例如:你想离开加入到 ID 上的 TableA,但前提是 TableA.Status = 'Active'),你需要把在联接上过滤,而不是在 where 中,否则您会从主表中过滤掉任何没有匹配 TableA 记录的行(即,您刚刚使用 where 过滤器将其变成了内部联接)。跨度>
【解决方案2】:

如果内部联接的ON 子句要求存在应该是可选的行,则后续的内部联接只会“基本上使”外部联接无效。在这种情况下,重新排序连接要么不起作用,要么无济于事;相反,唯一的解决方法是将内部联接更改为适当的外部联接。

因此,例如,这可以正常工作:

    SELECT *
      FROM person
 LEFT JOIN address
        ON person.address_id = address.id
INNER JOIN email
        ON person.email_id = email.id

并且相当于将左外连接(第 3-4 行)移到内连接(第 5-6 行)之后得到的结果;而这并没有按预期工作:

    SELECT *
      FROM person
 LEFT JOIN address
        ON person.address_id = address.id
INNER JOIN city
        ON address.city_id = city.id

因为第二个ON 子句只有在address.city_id 不为空时才能满足。 (在这种情况下,正确的解决方法是将内连接更改为左外连接。)

也就是说,我同意 Gordon Linoff 的观点,通常最好将内连接放在左外连接之前;这是因为内部连接倾向于表示更多“基本”限制,因此这种排序通常更具可读性。 (而且我同意 Gordon Linoff 和 Shawn 的观点,通常最好避免右外连接。)

【讨论】:

  • 另外值得注意的是,服务器的查询优化器可以以它认为可以提供最佳查询计划的任何方式对 JOIN 进行重新排序。
  • @Shawn 括号会影响这个吗?
  • @Nicholas 我认为这取决于您在括号内分组的内容。你打算用括号做什么?无论如何,除非你使用一些特定的提示来强制你的服务器使用特定的查询计划,它仍然会做它认为最好的事情。
  • 我认为"...is equivalent to what you'd get if you swapped the order of the two joins..." 存在歧义。通过交换,您是指 1. 人内部加入电子邮件,然后人离开加入地址,还是 2. 人内部加入地址,然后人离开加入电子邮件?我觉得您是在谈论第一种情况,而不是在第二种情况下直接交换 JOIN 关键字。但是我能确保我理解你吗?
  • @Nicholas:正确,我的意思是第一种解释。我现在调整了答案,使其更加明确。
【解决方案3】:

没有必须按特定顺序做事的概念。特定表达方式的选择会产生后果。

了解left join on 返回的内容:inner join on 行加上由空值扩展的不匹配的左表行。对于right join on & 右表行也是如此。 full join 也是如此。作为outer join 的一部分,始终知道您想要什么inner joininner join onwherehavingleft/right [原文如此] join on 删除任何由空值扩展的行之后,需要右/左表列不为空,即仅保留其inner join on 行,即“将外连接变为内连接”。你说的是那个。

您不必担心这一点。只需专注于编写返回您想要的查询。你的问题就像问,我应该避免除以零,因为它是未定义的还是加零,因为它什么都不做?你为什么要这样做,因为它没有做你想做的事?如果您正在编写错误的查询,请找出运算符的作用。 Is there any rule of thumb to construct SQL query from a human-readable description?

PS 我对left join 和何时删除其空扩展行的特征集中在关联的inner joinon 作为一个整体以及要求右表列为空。您对零件组织的选择会误导和阻碍您。 1.任意两张表都可以joinedon任意条件。 PK-FK 相等只是一个特例。 (PKs 和FKs 不需要查询。尽管它们确实暗示了对输入和结果的某些限制。)FKunique 列和其他列可以在输入上有空值。 PK 表示 unique not null。 2.“匹配列”和“没有任何东西会匹配 NULL”会混淆,因为根据on 的整个条件,匹配或不匹配的是行或行对。 3.“任何不匹配的行,包括来自 OUTER JOIN 结果的 NULL 将在成为 INNER JOIN 时被删除”--不,它取决于 onwhere 的整个条件。 4.“这将是极其罕见的”——无关紧要;要么某事可能发生,要么不能发生,要么查询错误,要么正确。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-03
    • 2013-05-02
    • 2013-03-07
    • 2013-10-28
    • 2015-01-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多