2

我刚刚找到了一个很棒的页面,其中包含不同连接的维恩图和执行它们的代码:http:
//www.codeproject.com/Articles/33052/Visual-Representation-of-SQL-Joins

我在查询中使用了“右排除连接”,维恩图如下所示:

右不包括连接图

这是代码:

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

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

4

3 回答 3

3

一、JOIN和RIGHT JOIN是做什么的?

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

修饰符,JOIN例如LEFT,INNER和控制您在记录不匹配时的行为- 当 A 中没有记录根据指定规则匹配B中的记录时,反之亦然OUTERRIGHTJOIN

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

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

桌子是右边的b,前面的都是左边的。

这是修饰符行为的摘要:

  • LEFT:保留左表中不匹配的记录,丢弃右表中的记录;
  • RIGHT:保留右表中不匹配的记录,丢弃左表中的记录;
  • INNER:仅保留匹配的记录,丢弃两个表中不匹配的记录;
  • OUTERor FULL: 保留所有记录,不管匹配。

视觉上正在发生什么?

想象一下,您有两个简单的表,它们的名称与您放入其中的表的名称相同。

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,您只保留在主题中没有匹配的最后两行。

于 2015-09-12T20:33:32.597 回答
2

RIGHT JOIN是 的简写RIGHT OUTER JOIN
考虑一下精美手册中的出色解释:

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

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

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

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

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

您的查询有:

WHERE sold_subjects.subject IS NULL 

原文在哪里说:

WHERE A.Key IS NULL

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

  • subjects.subject IS NULL并且没有包含 NULL 的行sold_subjects.subject
  • subjects.subject IS NULL和一些带有 NULL 的行sold_subjects.subject
  • subjects.subject IS NOT NULL但没有匹配的行sold_subjects

如果链接列之一可以为 NULL,并且您希望将 NULL 值视为实际(它们不是),即将 NULL 匹配为 NULL,则可以使用NULL 安全运算符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通常比简单的要慢=,只在需要的地方使用它。通常,您在定义NOT NULL的键列上连接表- 隐式(自动生成 PK 列NOT NULL)或显式。

于 2015-09-12T21:58:15.087 回答
2

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

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

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

于 2015-09-12T20:54:55.433 回答