【问题标题】:Explanation of code for right excluding join?不包括加入的权利的代码解释?
【发布时间】:2015-12-09 04:25:56
【问题描述】:

我刚刚发现了一个很棒的页面,其中包含不同连接的 Venn diagrams 以及执行它们的代码:
http://www.codeproject.com/Articles/33052/Visual-Representation-of-SQL-Joins

我在查询中使用了“Right Excluding Join”,维恩图如下所示:

这里是代码:

SELECT subjects.subject
FROM sold_subjects
RIGHT JOIN subjects
ON sold_subjects.subject = subjects.subject
WHERE sold_subjects.subject IS NULL 

我要求解释这段代码的实际作用,尤其是最后一行发生的情况。我知道我们正在加入两个具有相同主题的关系,但是当我们在最后一行将其中一个关系的主题设置为 NULL 时会发生什么?

【问题讨论】:

标签: sql postgresql join left-join right-join


【解决方案1】:

首先,JOIN和RIGHT JOIN是做什么的?

JOIN 从两个表中获取信息,并根据您在ONWHERE 子句中指定的规则将它们连接起来。

JOIN 修饰符,例如 LEFTINNEROUTERRIGHT 控制 JOIN不匹配记录 的情况下的行为 -- 当A中没有记录按照指定规则匹配B中的记录,反之亦然

为了理解这部分,将表A作为左表,将表B作为右表。当您有多个连接时,每个连接中的右表是名称紧邻JOIN 命令的表。

例如 FROM a1 LEFT JOIN ... LEFT JOIN b

b 表是右边的,前面的都是左边的。

这是修饰符行为的总结:

  • LEFT:保留左表不匹配的记录,丢弃右表的记录;
  • RIGHT:保留右表不匹配的记录,丢弃左表;
  • INNER:只保留匹配的记录,丢弃两个表中不匹配的记录;
  • OUTERFULL:保留所有记录,无论匹配。

视觉上发生了什么?

假设您有两个简单的表格,它们的名称与您放入其中的表格名称相同。

sold_subjects               subjects
subject                     subject
   1                           1
   2                           4
   3                           5
   4                           6

当您RIGHT JOIN 两个表时,您创建的第三个表如下所示:

joined_table
sold_subjects.subject    subjects.subject
   1                          1
   4                          4
  NULL                        5
  NULL                        6

请注意,主题 23 已经不在此子集中。

当您添加带有sold_subjects.subject IS NULLWHERE 子句时,您只保留最后两行主题不匹配

【讨论】:

  • 这里被严重低估的答案。先生,我赞扬你。
【解决方案2】:

正确的连接确保您将保留正确表的所有记录。如果与左表不匹配,则结果中源自左表的所有变量都将为空(因为不匹配)。

where 子句检查 lefttable.subject 的值是否为空。如果它不为空,那么显然连接成功。如果它为空,则连接不起作用,将此值留空。因此,根据定义,这个 where 子句将返回右表中与左表不匹配的所有记录,这正是维恩图所说的!

这是 SQL 中很常见的做法,可能会有用例。例如:左表是销售额,右表是客户,你想知道所有没有销售额的客户。

【讨论】:

    【解决方案3】:

    RIGHT JOINRIGHT OUTER JOIN 的简写。
    Consider the excellent explanation in the fine manual:

    LEFT OUTER JOIN 返回合格笛卡尔积中的所有行 (即所有通过其连接条件的组合行),加上一份 左侧表格中没有右侧的每一行 通过连接条件的行。此左侧行扩展到 通过为 右侧的列。请注意,只有JOIN 子句自身的条件是 在决定哪些行匹配时考虑。外部条件 之后应用。

    相反,RIGHT OUTER JOIN 返回所有连接的行,再加上一行 对于每个不匹配的右侧行(在左侧用空值扩展)。 这只是一种符号方便,因为您可以将其转换为 LEFT OUTER JOIN左右表切换。

    我的大胆强调。您的查询只是一种排除其他表中不存在的行的方法,并附有一个闪亮的流行词(“正确排除 JOIN” )。还有其他:

    现在,对于棘手的部分 - 或者您偏离原始的地方:

    但是当我们在最后一行将其中一个关系的主题设置为 NULL 时会发生什么?

    您的查询有:

    WHERE sold_subjects.subject IS NULL 
    

    原文是这样说的:

    WHERE A.<b>Key</b> IS NULL

    Key 应该暗示 NOT NULL。如果基础表列sold_subjects.subjectsubjects.subject 可以为NULL,则查询不起作用没有办法消除歧义该行是如何限定的:

    • subjects.subject IS NULL 并且在 sold_subjects.subject 中没有带 NULL 的行
    • subjects.subject IS NULLsold_subjects.subject 中的一些带有 NULL 的行
    • subjects.subject IS NOT NULLsold_subjects 中没有匹配的行

    如果其中一个链接列可以为 NULL,并且您希望将 NULL 值视为实际 (它们不是),即将 NULL 匹配到NULL,您可以使用NULL-safe operator IS NOT DISTINCT FROM 替换为反连接:

    SELECT s.subject
    FROM   subjects s
    LEFT   JOIN sold_subjects ss ON ss.subject IS NOT DISTINCT FROM s.subject
    WHERE  ss.subject IS NULL;
    

    还有更短的语法,使用更常用的LEFT JOIN,但其他方面相同。 IS NOT DISTINCT FROM 通常比简单的 = 慢,只在需要的地方使用它。通常,您在 defined NOT NULL 的键列上连接表 - 隐式(PK 列自动为 NOT NULL)或显式。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-08-12
      • 2017-06-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-21
      • 1970-01-01
      • 2021-09-13
      相关资源
      最近更新 更多