SQL Outer Join - 执行不当

Posted

技术标签:

【中文标题】SQL Outer Join - 执行不当【英文标题】:SQL Outer Join - improper execution 【发布时间】:2015-07-31 16:03:33 【问题描述】:

我正在学习 SQL,我已经学习了有关复数视觉的基础课程,现在我正在通过 Treehouse 使用 mysql,以及他们通过 MySQL 服务器设置的虚拟数据库。完成培训后,我将每天在工作中使用 SQLServer。

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

“我们有一个 'movies' 表,其中包含一个 'title' 和 'genre_id' 列以及一个 'genres' 表有一个 'id' 和 'name' 列。使用内部联接 将 'movies' 和 'genres' 表连接在一起,仅选择 首先是电影“标题”,其次是流派“名称”。”

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

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

--但是--

挑战的下一个问题我没有那么成功,我不确定我哪里出错了。我真的很想通过 JOINS 变得更好,并且挑选所有聪明人的大脑是我能想到的最好的方法来解释这个特定的(我敢肯定,对你们来说非常简单)问题。感谢您的帮助,这就是我难过的地方:

“像以前一样,带回电影“标题”和流派“名称”,但使用 正确的 OUTER JOIN 带回所有电影,无论是否 'genre_id' 是否设置。"

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

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

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

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

我知道这是完全菜鸟的东西,但就像我说的,我正在学习,我在 Stack 和整个互联网上研究的问题不一定针对同一个问题。我非常感谢您的专业知识和帮助。感谢您抽出宝贵时间阅读本文并在您选择时提供帮助!

【问题讨论】:

这是一个很好的阅读主题***.com/questions/38549/… 您的代码 SELECT movies.title, genres.name FROM movies LEFT OUTER JOIN genres ON movies.genre_id = genres.id 应该可以工作。你得到的结果不正确吗? 是的,它给了我以下信息:“太糟糕了!您没有先检索电影 'title',然后使用 'movies' 表中的所有信息检索流派 'name'。使用OUTER JOIN。如果电影表在左侧,则使用 LEFT;如果在语句右侧,则使用 RIGHT。" 还有@Raj More,这是一个很好的主题,非常感谢!我将继续使用它并最终在那里发布一个(不同的)问题。如果该代码似乎是正确的,则可能是他们系统中的错误。在遇到这种类型的问题之前我有两次 - 当我用我的条目的屏幕截图和由此产生的“不正确的条目”消息询问他们的帮助台时,他们无法解释为什么当代码出现时它没有工作正确...也许这里又是这种情况?不过,我倾向于在网站之前责备自己。我是新手,和所有菜鸟一样,容易出错。 我一直很喜欢 Jeff Atwood 的 this explanation of joins,因为我是一个视觉学习者。 【参考方案1】:

你的解决方案是正确的:

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

这是我的解释:

当你告诉“左连接”或“左外连接”时,其实,

并不是说“你不在乎在电影表中是否设置了genre_id”,

但是“您希望显示每部电影的所有类型,但是,您不在乎某些记录的电影表中是否未设置类型 ID;只需在这些情况下显示电影 [并显示 'genre = NULL ' 对于那些记录]"

通常,在“左连接”中,您希望:

左表的所有记录,以及其他表中的相应记录,如果有的话。否则为 NULL。

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

1- 已设置为流派的所有电影 (给出movie.title,Genres.name)

2- 所有其他电影 [没有类型,即,genre_id = NULL] (给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

【讨论】:

【参考方案2】:

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

我想补充一下关于 JOIN 的另一个观点,我认为这将有助于您了解将来如何使用它(之后,我还建议您点击此链接:SQL JOINS)。

这个视角是从 DB 的角度来看的,很“傻”,猜不出你真正想让它为你做什么。

我帮助它有帮助,不会混淆你太匹配:

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

假设这是一个电影列表:

    世界末日 蝙蝠侠 灰姑娘

以及流派列表:

    动作 奇幻 西部

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

    世界末日动作 世界末日幻想 世界末日西部 蝙蝠侠 动作 蝙蝠侠 奇幻 蝙蝠侠 西部 灰姑娘 动作 灰姑娘 幻想 灰姑娘 西方

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

在您的数据库中,您可以跟踪哪个电影是哪个流派(通过它的 id 识别流派),所以让我们谈谈新表,它们看起来像这样并包含有关电影流派的信息:

    1 - 世界末日 - 1 2 - 世界末日 - 2 4 - 蝙蝠侠 - 1 5 - 蝙蝠侠 - 2 6 - 蝙蝠侠 - 3 7 - 灰姑娘 - 2

还有类型:

    1 - 动作 2 - 幻想 3 - 西部

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

每次调用连接时(无论哪种连接:LEFT/RIGHT/OUTER/INNER),数据库都会创建一个包含所有可用选项的新表([表 1 行号][表 2 行号])。现在,您可能在想:DB 如何擦除我不想要的行?

    首先,您定义一个 ON 条件。你告诉你的数据库:“请为我标记所有符合我条件的行:movies.genre_id = genres.id(但不要删除任何未标记的行!!!)”。 其次,您告诉数据库您要删除(或编辑!!!)哪种类型的行:现在是 JOIN 类型,这有点棘手。

INNER JOIN 很容易理解 - 只需告诉数据库:“删除所有不符合我的条件的行:movies.genre_id = genres.id”(当然显示删除这些我不需要的行后,我更新的表)。

左/右连接更复杂。让我们以 LEFT JOIN 为例。你告诉你的数据库:“好吧,如果一行不符合我的条件:movies.genre_id = genres.id,将我的行的右侧部分(意思是代表我的第二个表的列)标记为空,然后离开该行. 这样,我就知道你在 table1 中的这一行,在 table2 中没有匹配的行。

RIGHT JOIN中,情况正好相反:你告诉数据库,如果你的条件不满足,将左边标记为空。

FULL JOIN 告诉您的数据库:“好吧,从不符合我的条件的行中,创建 2 行:1 将其 RIGHT 部分标记为 null ,第二个将其 LEFT 部分标记为空”(这对于理解为什么需要它的 hack 有点复杂,而且您几乎不需要在第一步中使用 FULL JOIN,所以放弃它现在)。

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

    首先,了解您想要得到什么,请参阅答案中的插图:SQL JOINS。 然后,您需要向 DB 解释它应该做什么: 首先,告诉它应该标记哪些行, 然后,告诉它应该删除/编辑哪些行。

【讨论】:

这太棒了,而且非常全面,@Captain Crunch,感谢您抽出宝贵的时间!在我有更多的实践和经验之前,我很可能会一次又一次地回到这一点。

以上是关于SQL Outer Join - 执行不当的主要内容,如果未能解决你的问题,请参考以下文章

SQL_连接(Join),内部连接(INNER JOIN),左连接(LEFT JOIN ),右连接(RIGHT JOIN)完整外部连接(FULL OUTER JOIN),自连接(Self JOIN)(

在 MySQL 中执行 FULL OUTER JOIN 查询时出错 [重复]

sql执行顺序

在 MYSQL 中执行 LEFT OUTER JOIN 时插入零而不是 NULL

mysql中inner join和outer join有啥区别?

使用 WHERE 子句中的过滤器优化 OUTER JOIN 查询。(查询规划器)