SQL 外部联接 - 执行不当

SQL Outer Join - improper execution

我正在学习 SQL,我已经学习了 pluralsight 的基础课程,现在我正在通过 Treehouse 使用 MySQL,他们已经建立了虚拟数据库,通过 MySQL服务器。培训完成后,我将每天在工作中使用 SQL服务器。

我 运行 昨天参加了一个由两部分组成的挑战,我遇到了一些麻烦。 挑战中的第一个问题是:

"We have a 'movies' table with a 'title' and 'genre_id' column and a 'genres' table which has an 'id' and 'name' column. Use an INNER JOIN to join the 'movies' and 'genres' tables together only selecting the movie 'title' first and the genre 'name' second."

了解如何正确设置 JOINS 让我有点困惑,因为这些概念看起来很简单,但就像在烹饪中一样,执行就是一切——我做错了。我 经过反复试验、工作并重新观看了几次 Treehouse 的解释后,能够弄清楚这一点;这是我如何解决第一个问题,并给出了 Treehouse 接受的答案:

SELECT movies.title, genres.name FROM movies INNER JOIN genres ON movies.genre_id = genres.id;

--但是--

挑战的下一个问题我做的不是很成功,我不确定我哪里做错了。我真的很想通过 JOINS 变得更好,并且采纳你们这些聪明人的想法是我能想到的最好的方法来解释这个特定的(我敢肯定,对你们来说简单得可怜)问题。感谢您的帮助,这就是我被难住的地方:

"Like before, bring back the movie 'title' and genre 'name' but use the correct OUTER JOIN to bring back all movies, regardless of whether the 'genre_id' is set or not."

这是我想出的最接近(?)的解决方案,但我显然在这里做错了(可能很多)错误:

SELECT movies.title, genres.name FROM movies LEFT OUTER JOIN genres ON genres.id;

我最初尝试过这个(如下)但是当它不起作用时,我决定删除语句的最后一部分,因为它在需求标准中提到我需要一个不关心的数据集电影中是否设置了genre_id table:

SELECT movies.title, genres.name FROM movies LEFT OUTER JOIN genres ON movies.genre_id = genres.id;

我知道这是 菜鸟的东西,但就像我说的,我正在学习,我在 Stack 和整个互联网上研究的问题不一定适合对于同样的问题。我非常感谢您的专业知识和帮助可以借鉴。感谢您花时间阅读本文,如果您选择阅读本文,请提供帮助!

您的解决方案是正确的:

SELECT movies.title, genres.name 
    FROM movies 
        LEFT OUTER JOIN genres ON movies.genre_id = genres.id

这是我的解读:

当你说“左连接”或“左外连接”时,实际上,

it's not that "You don't care if genre_id is set in the movies table or not",

but "You want all genres of each movie to be shown, however, you don't care if genre_id is not set in the movies table for some records; just show the movie in these cases [and show 'genre = NULL' for those records]"

一般来说,在“左连接”中,您需要:

all the records of the left table, with their corresponding records in the other table, if any. Otherwise with NULL.

在您的示例中,将显示这两组记录:

1- All the movies which have been set to a genre
(give movie.title, Genres.name)

2- All other movies [which do not have a genre, i.e., genre_id = NULL]
(give movie.title, NULL)

示例(左连接):

Title, Genre
--------------
Movie1, Comedy
Movie1, Dramma
Movie1, Family
Movie2, NULL
Movie3, Comedy
Movie3, Dramma
Movie4, Comedy
Movie5, NULL

示例(带内连接):

Title, Genre
--------------
Movie1, Comedy
Movie1, Dramma
Movie1, Family
Movie3, Comedy
Movie3, Dramma
Movie4, Comedy

您的具体问题已经得到解答,不过:

我想补充一下关于 JOIN 的另一个观点,我认为这将有助于您了解如何在未来使用它(之后,我也建议您遵循此 link:SQL JOINS).

这个视角是DB眼里的,"dumb"猜不出你到底想让它为你做什么

我帮你帮你,不会把你也弄糊涂了 match:

让我们先了解连接的作用(不使用任何 SQL 脚本),然后我们会更好地理解如何使用它。

假设这是一个电影列表:

  1. Armageddon
  2. Batman
  3. Cinderella

和流派列表:

  1. Action
  2. Fantasy
  3. Western

当您加入两个 tables 时,数据库会创建一个新的 tables,对于 movies table 中的每一行,您将获得所有可能的genres table 中的行,如下所示:

  1. Armageddon <-> Action
  2. Armageddon <-> Fantasy
  3. Armageddon <-> Western
  4. Batman <-> Action
  5. Batman <-> Fantasy
  6. Batman <-> Western
  7. Cinderella <-> Action
  8. Cinderella <-> Fantasy
  9. Cinderella <-> Western

还可以看到NEW table行号是3*3([table1行号] [table2 行号])。你能解释一下为什么吗?如果是这样,让我们​​继续我们的第二步...

在您的数据库中,您会跟踪哪部电影属于哪种类型(通过其 ID 识别类型),所以让我们谈谈新的 tables,它们看起来像这样并包含有关电影类型的信息:

  1. 1 - Armageddon - 1
  2. 2 - Armageddon - 2
  3. 4 - Batman - 1
  4. 5 - Batman - 2
  5. 6 - Batman - 3
  6. 7 - Cinderella - 2

流派:

  1. 1 - Action
  2. 2 - Fantasy
  3. 3 - Western

正如我们刚刚解释的那样,加入两个 table 将使您... 18 行(6*3=18。为什么?因为对于电影 table 中的每一行,您'将从 genres table) 中获取所有可能的行。那18行我就不写了,希望你明白我的意思...

每次你调用连接(不管是哪种连接:LEFT/RIGHT/OUTER/INNER),数据库都会创建一个新的table可传递的选项([table 1 行号] 乘以 [table 2 行号])。现在,您可能在想:数据库如何删除我不想要的行?

  1. 首先,您定义一个 ON 条件。你告诉你的数据库:"please mark for me all rows that meet my condition: movies.genre_id = genres.id (But don't drop any unmarked rows yet!!!)".
  2. 其次,您告诉您的数据库要删除(或编辑)哪种行!!!):现在是 JOIN 类型,这有点棘手。

INNER JOIN 很容易理解-只需告诉数据库:"drop all rows that don't meet my condition: movies.genre_id = genres.id"(当然还要告诉我更新后的table,在你删除这些我不需要的行之后)。

LEFT/RIGHT JOIN 更复杂。让我们从 LEFT JOIN 开始。您是在告诉您的数据库:“好吧,如果某行不符合我的条件:movies.genre_id = genres.id,请将我行的右侧部分(即代表我的第 2 个 table 的列)标记为null,并离开该行。 这样,我知道你在 table1 中的这一行在 table2 中没有匹配的行。

RIGHT JOIN中,它是相反的:你告诉数据库,如果你的条件不满足,标记LEFT站在 null 一边。

FULL JOIN 告诉你的数据库:"well, from a row that doesn't meet my condition, make 2 rows: 1 that has it's RIGHT part marked as null, and a second that has it's LEFT part marked as null"你会需要它,而且你几乎不需要在第一步中使用 FULL JOIN,所以暂时放弃它)。

总而言之,我在设计 JOIN 查询时给您的建议

  1. 首先,了解你想要得到什么,参见答案中的插图:SQL JOINS
  2. 然后,当你需要向你的数据库解释它应该做什么的时候:
    • 首先,告诉它应该标记哪些行,
    • 然后,告诉它应该在哪些行中 drop/edit。