在正确的情况下正确加入?

数据挖掘 sql
2021-09-16 09:00:20

(请原谅问题标题中的双关语。)

我目前正在教授数据科学的入门课程。

我了解左连接、右连接、内连接和完全连接之间的区别。但是,我不确定如何向学生解释特定联接(例如内部联接)何时是适合该特定情况的联接。

我正在寻找三个现实生活中的例子:

  • 在示例 A 中,内连接是最合适的。
  • 在示例 B 中,左/右连接是最合适的。
  • 在示例 C 中,完全连接是最合适的。

我不需要所有的细节,但我确实想要大局的想法,以表明在那个真实的例子中,这个连接是最合适的。

注意:我正在使用 R 包 dplyr 进行教学,所以我使用了dplyr 连接函数的名称。

3个回答

您是在线零售商。像亚马逊。您将不同类别商品的购买数据保存在不同的表格中,但所有网站用户都有一个具有一个 ID 的帐户。

内连接: 您有两个数据集,一个包含用户 ID 和购买服装数据,第二个数据集包含用户 ID 和购买书籍数据。您想找出谁从您的网站购买了衣服和书籍。

内部加入以查找购买衣服和书籍的人的用户 ID 和购买。没有购买这两种物品的任何用户都将被从决赛桌“淘汰”。

Left Join 你有一个数据集,其中包含所有用户的用户 ID 和帐户信息(例如年龄、姓名)。您希望构建此表以包含一些销售数据,而不会将人员从完整的用户列表中删除。因此,您将把购买数据集加入您的帐户数据集(以用户 ID 作为键)。任何未进行购买的用户都不会从您的决赛桌中删除。

右连接 与左连接相反。例如,您希望保留所有购买数据,即使出于某种原因您的帐户信息表不包含进行该购买的用户的 ID。

完全(外部)加入 您想加入帐户信息和购买表,但您不想丢失任一表中的任何条目。因此,您的决赛桌将包括没有购买的用户,以及(可能是神秘的)没有与他们关联的用户的购买。

您可以使用维恩图来解释它们。

在此处输入图像描述

在此处输入图像描述

在此处输入图像描述

在此处查看有关查询和示例的更多详细信息

以一个具有三个表的“学校”的假想数据库为例:

  • 学生(学生证、姓名)
  • 课程(CourseID、名称)
  • 注册(StudentID、CourseID)

在这种情况下,您可以按如下方式解释连接:

内连接将是回答诸如“该学生注册了哪些课程”或“该学生注册了哪些课程”之类的查询的自然操作。

但是,如果学生没有注册任何课程,则上面的查询将简单地不返回任何行,而您可能仍希望在输出中有一行包含学生姓名和 NULL/NA 值作为其唯一的“课程”。在这种情况下,您可能更喜欢left join

如果您稍后需要进行一些聚合,则对左/右/外连接的需求更为常见。假设您需要输出一个表格,列出所有课程以及注册学生的数量。使用内部连接只会列出至少有一名学生的课程。使用左连接将列出所有这些,包括那些有 0 个学生的。

右连接有点深奥,很少使用(我写了很多 SQL,但我认为到目前为止从未使用过右连接)。实际上,您始终可以使用左连接代替右连接,而且大多数时候人们倾向于以“从左到右”的方式考虑数据访问。我看到的使用右连接的三种可能情况是:

  1. 如果你不知何故倾向于以从右到左的方式“思考”。假设您想列出课程以及注册的学生人数。“从左到右”的思路如下:首先选择所有课程,然后左连接所有注册,然后聚合。

    你也可能有不同的想法。毕竟,您想要开始的“重要”数据源是 Enrollments 表,那么为什么不从读取数据开始,甚至可能先聚合它。然后,您可以加入 Courses 表以获取课程名称来代替 ID。在这种情况下,您将正确加入课程。

  2. 如果您怀疑右连接会更有效。假设在上面的示例中,有数千门课程,其中只有几个是非空的,有数百名学生。在这种情况下,执行“Courses left join Enrollments”查询的“直接”方式是扫描 Courses 表,尝试通过扫描 Enrollments 表来匹配每个课程(假设查询优化器是哑的并且没有索引在表格上,为了举例——毕竟 dplyr 中是否有查询优化器?)。

    只有两门课程会匹配,但扫描必须进行一千次。结果表将有两个非空课程名称为每个注册学生重复数百次,以及数千个具有 NULL 学生的课程名称,之后您将继续进行聚合。

    相反,如果我们先聚合 Enrollments,然后以“从右到左”的方式右连接课程名称,聚合的 Enrollments 表将只有两行,因此只对 Courses 表执行两个 ID 匹配(按原样写出剩余的课程名称)。

    幸运的是,如今大多数 SQL 数据库引擎都足够智能,可以在内部处理此类优化,而无需用户手动调整查询中连接的方向和顺序。

  3. 最后,有时您以编程方式生成 SQL在这种情况下,将课程或学生名称“加入”到某些先前计算的主结果表的需求可能很常见,并且右连接非常合适。

对于右连接的正确情况,这是一个很长的题外话,让我们回到外连接根据我的经验,它也很少使用。他们说外部连接对于 SQL 引擎来说更难优化(尽管我现在不能确切地看到为什么会这样)。无论如何,在我们的示例中,可以使用外连接来创建表格(课程,学生列表)的表格,并带有两个额外的条件:

  • 将包括所有空课程,将他们的学生列表显示为单个 NULL 条目,
  • 会有一个特殊的 NULL 课程,列出所有没有在任何地方注册的学生。

那可能是一张非常有用的桌子,对吧?