右边排除连接的代码说明?

时间:2015-09-12 20:15:30

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

我刚刚找到了一个包含Venn diagrams个不同联接的精彩页面以及执行它们的代码:
http://www.codeproject.com/Articles/33052/Visual-Representation-of-SQL-Joins

我在查询中使用了“Right Excluding Join”,维恩图看起来像这样:

right excluding join diagram

这是代码:

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

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

3 个答案:

答案 0 :(得分:2)

首先,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主题已经消失。

当您使用WHERE添加sold_subjects.subject IS NULL子句时,您只保留最后两行主题不匹配

答案 1 :(得分:2)

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

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

这是SQL中非常常见的做法,也有用例。例如:左表是销售,右表是客户,您想要了解所有没有销售的客户。

答案 2 :(得分:2)

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

  

LEFT OUTER JOIN返回合格笛卡尔积中的所有行   (即,通过其连接条件的所有组合行),加上一个副本   左侧表中没有右手的每一行   传递连接条件的行。这个左手行延伸到   通过插入空值来连接表的全宽度   右栏。请注意,只有JOIN子句的条件是   在决定哪些行匹配时考虑。外面的条件   之后适用。

     

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

大胆强调我的。您的查询只是 一种 方式,可以排除另一个表中不存在的行,附加一个闪亮的热门词(" Right排除JOIN&#34 ; )。还有其他人:

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

  

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

您的查询有:

WHERE sold_subjects.subject IS NULL 

原文说:

WHERE A.Key IS NULL

Key应该暗示 NOT NULL 。如果基础表列sold_subjects.subjectsubjects.subject中的任何一个可以为NULL,则查询只是不起作用。会有无法消除行符合条件的方式:

  • subjects.subject IS NULLsold_subjects.subject
  • 中没有NULL行
  • subjects.subject IS NULL以及sold_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)或显式连接。