MySQL:联接类型的快速细分


157

我想快速细分MySQL联接的类型。我知道这些,其余的我不确定它们是什么意思。

  • 逗号分隔(这到底是什么缩写?):SELECT * FROM a, b WHERE b.id = a.beeId AND ...
  • 显示来自a的信息,即使b中没有匹配项: SELECT * FROM a LEFT OUTER JOIN b ON b.id = a.beeId WHERE ...

我看过其他联接,但是想知道是什么使它们与众不同,INNER/ 是什么OUTER,确实增加了LEFT更改。

我已经知道联接的工作方式,我只想知道是否还有其他类型的联接,或者它们只是获得相同结果的不同方式。


Answers:


463

3
+1,但都缺少cross join,这会产生笛卡尔积。
Denis de Bernardy 2011年

11
@denis:请仔细阅读codinghorror.com链接:There's also a cartesian product or cross join, which as far as I can tell, can't be expressed as a Venn diagram:
Rufinus

1
我很惊讶,将这些图表打印并放在我的办公室墙上。你改变了我的生活!
yossico 2014年

41
问题是关于MySQL的。MySQL不支持FULL OUTER联接。
Mike Baranczak 2014年

4
当然,这应该是不发布此主题的原因。
Rufinus 2014年

27

根据您的评论,最好在W3Schools中找到 每个类型的简单定义。每种类型的第一行简要说明联接类型。

  • JOIN:当两个表中至少有一个匹配项时,返回行
  • 左联接:即使左表中没有匹配项,也返回左表中的所有行
  • RIGHT JOIN:即使左侧表中没有匹配项,也返回右侧表中的所有行
  • FULL JOIN:当其中一张表匹配时返回行

结束编辑

简而言之,您用逗号分隔的示例

SELECT * FROM a, b WHERE b.id = a.beeId AND ...

正在从表a和b中选择每条记录,并用逗号分隔各表,这也可以用在诸如

SELECT a.beeName,b.* FROM a, b WHERE b.id = a.beeId AND ...

然后,它将在示例中b.id列和a.beeId列匹配的行中获取指示信息。因此,在您的示例中,它将从表a和b获取所有信息,其中b.id等于a.beeId。在我的示例中,当b.id等于a.beeId时,它将从b表中获取所有信息,而仅从a.beeName列中获取信息。请注意,还有一个AND子句,这将有助于优化结果。

有关mySQL联接和左联接的一些简单教程和说明,请查看Tizag的mySQL教程。您也可以访问Keith J. Brown的网站,以获取有关联接的更多信息,这也非常好。

我希望这可以帮助你


碰巧我已经知道了这一切。我实际上是在寻找连接的类型。抱歉,我不清楚我所知道的内容。但是我并不是为了获得快速摘要而寻找冗长的文档。
布莱恩·菲尔德

答案中的另一个参考...可能更多是您想要的伴侣。
瑞安

对该编辑+1。我并不像某些人那样对W3Schools有偏见。也许我没有看到太多的弊端,或者也许这只是一场“圣战”。另外,我编辑了W3Schools的内容,希望您不要介意,但可以随时进行所需的任何编辑。接受的答案中的所有视觉效果都不错,但实际上实际上是同一联接的变体。这是一个很好的选择。
布赖恩·菲尔德

谢谢乔治,我完全不介意,只要编辑正确!我相信人们需要找到适合他们的资源,或多或少的信息,很多例子,甚至没有。W3Schools的语言准确而简洁,他们往往也有很好的例子,Tizag也很相似。放轻松吧
Ryan

1
mysql中没有FULL JOIN,因此这些链接不是很有用。
以太

13

我有2张桌子,像这样:

> SELECT * FROM table_a;
+------+------+
| id   | name |
+------+------+
|    1 | row1 |
|    2 | row2 |
+------+------+

> SELECT * FROM table_b;
+------+------+------+
| id   | name | aid  |
+------+------+------+
|    3 | row3 |    1 |
|    4 | row4 |    1 |
|    5 | row5 | NULL |
+------+------+------+

INNER JOIN关心两个表

INNER JOIN关心两个表,因此如果两个表都有一个,则只获得一行。如果有多个匹配对,您将获得多行。

> SELECT * FROM table_a a INNER JOIN table_b b ON a.id=b.aid;
+------+------+------+------+------+
| id   | name | id   | name | aid  |
+------+------+------+------+------+
|    1 | row1 |    3 | row3 | 1    |
|    1 | row1 |    4 | row4 | 1    |
+------+------+------+------+------+

如果您颠倒顺序,则对INNER JOIN没什么影响,因为它关心两个表:

> SELECT * FROM table_b b INNER JOIN table_a a ON a.id=b.aid;
+------+------+------+------+------+
| id   | name | aid  | id   | name |
+------+------+------+------+------+
|    3 | row3 | 1    |    1 | row1 |
|    4 | row4 | 1    |    1 | row1 |
+------+------+------+------+------+

您得到相同的行,但列的顺序不同,因为我们以不同的顺序提到了表。

LEFT JOIN只关心第一个表

LEFT JOIN关心您提供给它的第一个表,而不关心第二个表,因此即使第二个表中没有对应的行,也总是从第一个表中获取行:

> SELECT * FROM table_a a LEFT JOIN table_b b ON a.id=b.aid;
+------+------+------+------+------+
| id   | name | id   | name | aid  |
+------+------+------+------+------+
|    1 | row1 |    3 | row3 | 1    |
|    1 | row1 |    4 | row4 | 1    |
|    2 | row2 | NULL | NULL | NULL |
+------+------+------+------+------+

在上方您可以看到table_a的所有行,即使其中某些行与表b中的任何内容都不匹配,但不是table_b的所有行-仅与table_a中的某些内容匹配的行。

如果我们反转表的顺序,则LEFT JOIN的行为将有所不同:

> SELECT * FROM table_b b LEFT JOIN table_a a ON a.id=b.aid;
+------+------+------+------+------+
| id   | name | aid  | id   | name |
+------+------+------+------+------+
|    3 | row3 | 1    |    1 | row1 |
|    4 | row4 | 1    |    1 | row1 |
|    5 | row5 | NULL | NULL | NULL |
+------+------+------+------+------+

现在,我们获得了table_b的所有行,但仅匹配了table_a的行。

RIGHT JOIN只关心第二张桌子

a RIGHT JOIN b使您的行与完全相同b LEFT JOIN a。唯一的区别是列的默认顺序。

> SELECT * FROM table_a a RIGHT JOIN table_b b ON a.id=b.aid;
+------+------+------+------+------+
| id   | name | id   | name | aid  |
+------+------+------+------+------+
|    1 | row1 |    3 | row3 | 1    |
|    1 | row1 |    4 | row4 | 1    |
| NULL | NULL |    5 | row5 | NULL |
+------+------+------+------+------+

这与table_b LEFT JOIN table_a在LEFT JOIN部分中看到的行相同。

类似地:

> SELECT * FROM table_b b RIGHT JOIN table_a a ON a.id=b.aid;
+------+------+------+------+------+
| id   | name | aid  | id   | name |
+------+------+------+------+------+
|    3 | row3 | 1    |    1 | row1 |
|    4 | row4 | 1    |    1 | row1 |
| NULL | NULL | NULL |    2 | row2 |
+------+------+------+------+------+

与相同的行table_a LEFT JOIN table_b

完全没有连接可以为您提供所有内容的副本

No Join子句:如果您编写的表根本没有JOIN子句,只是用逗号隔开,那么您将以每种可能的组合在第二个表的每一行旁边写入第一个表的每一行:

> SELECT * FROM table_b, table_a;        
+------+------+------+------+------+
| id   | name | aid  | id   | name |
+------+------+------+------+------+
|    3 | row3 | 1    |    1 | row1 |
|    3 | row3 | 1    |    2 | row2 |
|    4 | row4 | 1    |    1 | row1 |
|    4 | row4 | 1    |    2 | row2 |
|    5 | row5 | NULL |    1 | row1 |
|    5 | row5 | NULL |    2 | row2 |
+------+------+------+------+------+

(这是从我的博客文章“ SQL连接类型示例”中得出的)


@Anu当您的信誉低下意味着您的编辑必须由其他人进行审查,您正在浪费他们的时间时,请不要进行如此琐碎的编辑。该编辑应该没有差异而被拒绝。您更改的代码实际上并没有错,您可以发表评论。
philipxy

@philipxy好的。注意到这一点。当我试图理解解释时,我看到了这样的错字,这就是为什么要对其进行编辑以使其更清晰。确实,这是一个很好的答案,我的意图是使其更加正确。
阿努

@Anu该答案与大多数答案中的零散不完整描述相同。它实际上并没有说输出是输入的函数。另请参阅两页上建议的重复项中的几乎所有答案以及我的评论。另请参阅我的答案。附注:我从昨天起就认真地看到了这一点,重新审查了编辑大小(当然,Meta Stack OverflowMeta Stack Exchange上还有更多相关文章。)
philipxy

11

mysql中不存在完全外部联接,您可能需要使用左右联接的组合。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.