自我加入。内部、外部或左侧重要吗?

Self joins. Does Inner, Outer, or Left matter?

我想知道这一点,因为自连接只需要一个 table,所以感觉这不会有什么不同。 我读过这个问题:Explanation of self-joins。 有几个答案,他们使用不同类型的连接来完成看似相同的任务。

所以有没有区别?如果是这样,你能举个例子吗?

它确实有所作为。有很多方法可以从概念上考虑它。
在某种程度上,连接意味着您希望尽可能使用一行而不是两行。你基本上是拿两个 table,然后用它们制作一个 table。

我认为理解内部、right/left 和外部之间的最佳方式是 tables

    **FULL Outer:**
name           number
john           
jamie          7
ann            10
              11
              12

一些行缺少元素,因为外连接使用每个 table 中的每一个可能的行。在这种情况下,无论我们选择什么作为我们的链接器(即 "ON" 之后的链接器),John 都有一个不对应于我们第二个 table 中的任何行的链接器值。 11 和 12 是第二个 table 中的数字,它们没有与另一个名称

中的名称匹配的链接器值

Inner 意味着如果您的 table 中的一个元素没有与另一个 table 共有的数据成员,那么我们必须跳过这些元素。所以 table 变成

   **INNER**
    name      number
   jamie      7
    ann       10
如果从抽象的角度考虑

Left/right 连接,它们是同一件事,因为这些连接中的每一个都会导致 table 之一显示其完整的元素集, 而另一个仅限于那些在另一个 table 中有伙伴的人。 Left/right是外连接,但基本上只是半外连接。

    **left/right:**


   name           number
   lee
   john           
   jamie          7
   ann            10



   name           number           
   jamie          7
   ann            10
                  15
                  29

Explanation of self-joins 以他给出的内部连接为例。但是如果有一些Boss列出的员工在员工table中找不到,甚至是空值怎么办?如果有员工在员工 table 中列出了老板,但老板不在老板 table 中怎么办?或者也许员工根本没有列出老板? (这实际上是现实的,因为有些人是个体经营者)

然后我们必须决定,我们究竟要查询什么?我们需要对个体经营者进行核算吗?如果是这样,则排除了 INNER JOIN。所以现在我们必须决定是否要将没有员工的老板包括在数据库中。

现实地思考,我可以想象我们会进行左连接或右连接。

首先,left join是一个outer join

它确实有所不同,因为 inner joinleft join 的定义在实现自连接时也是相同的。因此,假设您有一个典型的 Employee table 和经理。现在为了争论起见,假设一名员工的经理不在员工名单中。因此,如果您进行典型的自连接,您将不会获得该记录。但是在 left join 的帮助下,您可以返回该记录。

left join 的另一个用途是查找 left table 但不在 right 中的记录,方法是使用 where 子句作为 where right_table.key is null。您也可以为自连接实现相同的效果,这是您无法通过内部连接实现的。

这里有一些解释上述情况的查询,您可以看到使用 left join 可以做的额外事情,但不能使用 inner join

http://rextester.com/HICA42440

这完全取决于您要对数据执行的操作。 This 答案很好地详细说明了自我内部联接的外观。我最近写了一份报告,要求比较学生连续修读的两门课程的成绩。它是这样的:

给定一个 table student_course:

STUDENT_ID  COURSE  GRADE
1           MTH251  A
1           MTH252  B
2           MTH251  A
2           MTH252  A
3           MTH251  B
3           MTH252  C

查询:

SELECT course1.student_id
  , course1.course AS course1
  , course1.grade AS grade1
  , course2.course AS course2
  , course2.grade AS grade2
FROM student_course course1
INNER JOIN student_course course2
  ON course1.student_id = course2.student_id
WHERE course1.course = 'MTH251'
  AND course2.course = 'MTH252';

Fiddle here. 抱歉,PostgreSQL fiddle 不适合我,所以我使用 Oracle 进行测试。 PostgreSQL 等效项看起来应该大致相同。

现在说我想见一个可能没有参加过 MTH252 的学生。你可以这样做:

SELECT course1.student_id
  , course1.course AS course1
  , course1.grade AS grade1
  , course2.course AS course2
  , course2.grade AS grade2
FROM student_course course1
LEFT OUTER JOIN student_course course2
  ON course1.student_id = course2.student_id
  AND course2.course = 'MTH252'
WHERE course1.course = 'MTH251';

Other Fiddle

前者显示同时修读MTH251和MTH252的学生,后者显示修读MTH251的学生,而不管他们是否完成了MTH252。

如 Nick.McDermaid 所述,自连接的工作方式与连接两个具有不同数据的 table 完全相同。

LEFT (OUTER) JOIN ON 根据定义给出 INNER JOIN ON 给出的行加上左侧不匹配的行,由 NULL 扩展。因此,如果每个左行都匹配,那么他们会给出相同的答案。特别是,如果 ON 条件等于左侧 table 的非 NULL FK(外键)引用 PK(主键)或另一个中的 UNIQUE NOT NULL,则每个左侧行都有一个匹配项,并且它们给出相同的答案。 RIGHT JOIN 和右 table.

也是如此

所以在 LEFT self-JOIN 中,如果每个左边的行都匹配,那么他们会给出相同的答案。特别是如果 ON 条件等于它引用其 PK(主键)的非 NULL FK(外键)或其中的 UNIQUE NOT NULL,则每一行都有一个匹配项并且它们给出相同的答案。

例如,如果每个员工都有一个经理,那么在 EMPLOYEE(e,...,m)NULL FOREIGN KEY (m) REFERENCES PK (e) 中,所以 LEFT self-JOIN ON left.m = right.e 给出相同的结果INNER.

PS 当你有一个假设时,你可以寻找可能恰好反驳它的反例。几乎任何小的随机值自连接都会反驳你的。你尝试过吗?如果你有 "feeling" 关于一些特殊情况的假设,你可以再做一次。