自然连接和内连接的区别
Posted
技术标签:
【中文标题】自然连接和内连接的区别【英文标题】:Difference between natural join and inner join 【发布时间】:2012-01-31 13:19:21 【问题描述】:自然连接和内部连接有什么区别?
【问题讨论】:
这个问题不是另一个问题的重复,因为这是关于 INNER 与 NATURAL 连接的问题,其他问题没有解决。 有一次,它作为What is the difference between left, right, outer and inner joins 的副本被关闭,但该问题并未解决内部连接和自然连接之间的区别。 【参考方案1】:INNER JOIN 和 NATURAL JOIN 之间的一个显着区别是返回的列数。
考虑:
TableA TableB
+------------+----------+ +--------------------+
|Column1 | Column2 | |Column1 | Column3 |
+-----------------------+ +--------------------+
| 1 | 2 | | 1 | 3 |
+------------+----------+ +---------+----------+
Column1 上 TableA 和 TableB 的 INNER JOIN
将返回
SELECT * FROM TableA AS a INNER JOIN TableB AS b USING (Column1);
SELECT * FROM TableA AS a INNER JOIN TableB AS b ON a.Column1 = b.Column1;
+------------+-----------+---------------------+
| a.Column1 | a.Column2 | b.Column1| b.Column3|
+------------------------+---------------------+
| 1 | 2 | 1 | 3 |
+------------+-----------+----------+----------+
Column1 上 TableA 和 TableB 的 NATURAL JOIN
将返回:
SELECT * FROM TableA NATURAL JOIN TableB
+------------+----------+----------+
|Column1 | Column2 | Column3 |
+-----------------------+----------+
| 1 | 2 | 3 |
+------------+----------+----------+
避免重复列。
(来自标准语法的 AFAICT,您不能在自然连接中指定连接列;连接严格基于名称。另见 Wikipedia。)
(内部连接输出中有一个作弊;a.
和 b.
部分不会出现在列名中;你只会有 column1
、column2
、column1
、 column3
作为标题。)
【讨论】:
我有两个表 TableA(Column1,Column2) 和 TableB(Column2,Column3)。 折叠输出中的列是自然连接中最不重要的方面。您需要知道的事情是(A)它会自动加入同名字段,并且(B)它会在您最不期望的时候搞砸您的 s***。在我的世界里,使用自然连接是解雇的理由。 @JonofAllTrades 你能解释一下NATURAL JOIN
究竟会毁掉什么,为什么会出乎意料,以及你所处的世界吗?
这在 user166390 的回答中有所解决。假设你在Customers
和Employees
之间有一个自然连接,加入EmployeeID
。 Employees
也有一个 ManagerID
字段。一切安好。然后,有一天,有人在Customers
表中添加了一个ManagerID
字段。您的加入不会中断(那将是一个怜悯),相反,它现在将包含第二个字段,并且不正确地工作。因此,一个看似无害的变化可能会破坏一些只是遥远相关的东西。很坏。自然连接的唯一好处是节省了一点打字时间,而缺点是巨大的。
@Jonathan,关于您的回答,您说SELECT * FROM TableA INNER JOIN TableB USING (Column1)
给出了 4 列。这是不正确的,因为 SELECT * FROM TableA INNER JOIN TableB USING (Column1)
和 SELECT * FROM TableA NATURAL JOIN TableB
是相等的,它们都给出 3 列。【参考方案2】:
inner 连接是连接表中的匹配行需要从第一个表返回的行
外部连接是连接表中的匹配行不需要返回第一个表中的行
自然联接是一种联接(您可以使用natural left
或natural right
),它假定联接条件与两个表中的同名列匹配
我会避免像瘟疫那样使用自然连接,因为自然连接是:
【讨论】:
我认为应该提到外部的左/右(因为完全提到了外部)。但除此之外,简洁明了:它只缺少漂亮的示例 SQL 记录图。 自然左和自然右也存在。但是,是的,仍然避免它们。 @Bohemian,关于“像瘟疫一样避免它们”,自然连接有实际用例,它们派上用场。 mariadb.com/kb/en/sql-99/natural-join "...只有当数据库命名约定正式且强制执行时,才会出现看似随意的“书籍NATURAL JOIN Checkouts
”..."
@sqlvovel 您的评论有很多问题,特别是不正确。连接列不能“在选择列表中指定”。自然连接的定义是连接*所有 类似命名的列*。来自 mysql 文档:两个表的 NATURAL [LEFT] JOIN 被定义为在语义上等同于 INNER JOIN 或 LEFT JOIN,其中包含命名两个表中存在的所有列的 USING 子句。。还有一件事——在实践中它是无用的,因为id
无处不在,加入也无用;通常的外键名称是tablename_id
。自然连接是一个坏、坏、坏的主意。
我的查询中没有双返回列。 NJ 语义的优点之一是永远不会返回重复的列。您之前的查询也比我的“不太安全”,因为如果将名为“a”的列添加到 t2(因为非别名连接条件不明确),它将失败。我怀疑您对 NJ 的偏见是基于您没有在标准 SQL 得到适当支持的产品中尝试过的事实。这里的问题是关于 SQL,而不是 MySQL - 完全不同的事情。你仍然没有更正你关于它是非标准的答案。【参考方案3】:
自然连接只是避免键入的快捷方式,假设连接很简单并且匹配同名字段。
SELECT
*
FROM
table1
NATURAL JOIN
table2
-- implicitly uses `room_number` to join
和...一样
SELECT
*
FROM
table1
INNER JOIN
table2
ON table1.room_number = table2.room_number
但是,您不能使用快捷方式格式进行更复杂的连接...
SELECT
*
FROM
table1
INNER JOIN
table2
ON (table1.room_number = table2.room_number)
OR (table1.room_number IS NULL AND table2.room_number IS NULL)
【讨论】:
@JonathanLeffler - 当然是在 MySQL 中。 好的 - 很有趣。我问是因为 SQL 标准似乎不允许这样做(但扩展总是可能的)。 哪个 DBMS 允许这种非标准语法:NATURAL JOIN ... USING ()
?标准是a NATURAL JOIN b
或a JOIN b USING (c)
“只是避免打字的捷径”是错误的陈述。它最显着的特点是它不会导致重复的列。
...例如,使用自然联接的查询结果将只有一列名为 room_number
,而您的内部联接将有两列名为 room_number
。【参考方案4】:
SQL 在很多方面并不忠实于关系模型。 SQL 查询的结果不是关系,因为它可能包含具有重复名称的列、“匿名”(未命名)列、重复行、空值等。SQL 不将表视为关系,因为它依赖于列排序等。
SQL 中NATURAL JOIN
背后的想法是更容易更忠实于关系模型。两个表的NATURAL JOIN
的结果将包含按名称去重的列,因此没有匿名列。同样,提供UNION CORRESPONDING
和EXCEPT CORRESPONDING
是为了解决SQL 对旧UNION
语法中列顺序的依赖问题。
但是,与所有编程技术一样,它需要纪律才能发挥作用。成功的NATURAL JOIN
的一个要求是一致地命名列,因为连接隐含在具有相同名称的列上(遗憾的是,在 SQL 中重命名列的语法很冗长,但副作用是在命名列时鼓励纪律基表和VIEW
s :)
请注意,SQL NATURAL JOIN
是一个等值连接**,但这并没有妨碍其实用性。考虑一下如果NATURAL JOIN
是SQL 中唯一支持的连接类型,它仍然是relationally complete。
虽然确实可以使用 INNER JOIN
和投影 (SELECT
) 编写任何 NATURAL JOIN
,但使用乘积 (CROSS JOIN
) 和限制 ( WHERE
);进一步注意,没有共同列名的表之间的NATURAL JOIN
将给出与CROSS JOIN
相同的结果。因此,如果您只对关系的结果感兴趣(为什么不呢?!)那么NATURAL JOIN
是您需要的唯一连接类型。当然,从语言设计的角度来看,INNER JOIN
和CROSS JOIN
等速记确实有其价值,但还要考虑到几乎任何 SQL 查询都可以用 10 种语法不同但语义相同的方式编写,这就是使得 SQL 优化器很难开发。
以下是一些语义等价的示例查询(使用the usual parts and suppliers database):
SELECT *
FROM S NATURAL JOIN SP;
-- Must disambiguate and 'project away' duplicate SNO attribute
SELECT S.SNO, SNAME, STATUS, CITY, PNO, QTY
FROM S INNER JOIN SP
USING (SNO);
-- Alternative projection
SELECT S.*, PNO, QTY
FROM S INNER JOIN SP
ON S.SNO = SP.SNO;
-- Same columns, different order == equivalent?!
SELECT SP.*, S.SNAME, S.STATUS, S.CITY
FROM S INNER JOIN SP
ON S.SNO = SP.SNO;
-- 'Old school'
SELECT S.*, PNO, QTY
FROM S, SP
WHERE S.SNO = SP.SNO;
** 关系自然连接不是等值连接,它是一个的投影。 - 菲利普西
【讨论】:
关系自然连接不是等值连接,它是一个的投影。 SQL 自然连接是一种 SQL 等连接(可能重复)——它是根据内部连接使用定义的。 @philipxy:谢谢,我已经进行了修改。请随时编辑 - 这个或我的任何答案 - 错误陈述和误解。我还在向你学习:)【参考方案5】:NATURAL
连接只是 特定 INNER
连接的简短语法 - 或“等连接” - 并且,一旦语法被解包,它们都表示相同的关系代数手术。这不是一种“不同类型”的连接,就像 OUTER
(LEFT
/RIGHT
) 或 CROSS
连接的情况。
请参阅 Wikipedia 上的 equi-join 部分:
自然联接提供了等值联接的进一步专业化。 连接谓词通过比较两个表中所有列在连接表中具有相同列名而隐式出现。生成的连接表只包含一个列同名列。
大多数专家都同意 NATURAL JOIN 是危险的,因此强烈反对使用它们。危险来自于无意中添加了一个与另一列同名的新列...
也就是说,所有NATURAL
连接都可以写成INNER
连接(但反过来不成立)。为此,只需显式地创建谓词——例如USING
或 ON
-- 并且,正如 Jonathan Leffler 指出的那样,如果需要,请选择所需的结果集列以避免“重复”。
编码愉快。
(NATURAL
关键字也可以应用于 LEFT
和 RIGHT
连接,同样适用。NATURAL LEFT/RIGHT
连接只是 特定 @987654336 的简短语法@加入。)
【讨论】:
"NATURAL join 只是 [snipped] "equi-join" 的简短语法——而且,一旦语法被解包,它们都代表相同的关系代数”——你是对的:这是真的关系代数,但你的答案在那之后就崩溃了,例如“大多数专家都认为 NATURAL JOIN 很危险,因此强烈反对使用它们”——关系代数领域的专家这么说的?! "NATURAL join 只是 [snipped] "equi-join" 的简短语法 不,自然 nner join 是(可以合理地称为 an 的形式的内部连接)equijoin 的投影。另外有内部和外部自然连接。【参考方案6】:自然连接:是两个表中所有列的组合或组合结果。 它将返回第一个表相对于第二个表的所有行。
内连接:除非任何列名在两个表中相同,否则此连接将起作用
【讨论】:
我认为您的答案不够清楚,需要大量重写才能解决。【参考方案7】:自然连接是基于所有公共列连接 2 个表。
common column :是在两个表中具有相同名称的列 + 在两个表中具有兼容的数据类型。 您只能使用 = 运算符
内连接是根据 ON 子句中提到的公共列连接 2 个表。
common column :是在两个表中具有兼容数据类型但不需要具有相同名称的列。
您只能使用任何比较运算符,例如=
、<=
、>=
、<
、>
、<>
【讨论】:
【参考方案8】:不同之处在于 int inner(equi/default)join 和 natural join 中的 natuarl 公用列 win 将单次显示,而 inner/equi/default/simple join 公用列将显示两次。
【讨论】:
【参考方案9】:内连接和自然连接几乎相同,但它们之间存在细微差别。不同之处在于自然连接不需要指定条件,但内部连接条件是强制性的。如果我们确实在内部连接中指定了条件,那么结果表就像一个笛卡尔积。
【讨论】:
为什么不需要指定加入条件?在什么情况下,在内连接中指定条件会产生类似于笛卡尔积的结果? 将外部和内部联接称为“几乎相同”有点轻描淡写,恕我直言。也许您可以详细说明您的评估?【参考方案10】:mysql> SELECT * FROM tb1 ;
+----+------+
| id | num |
+----+------+
| 6 | 60 |
| 7 | 70 |
| 8 | 80 |
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
+----+------+
6 rows in set (0.00 sec)
mysql> SELECT * FROM tb2 ;
+----+------+
| id | num |
+----+------+
| 4 | 40 |
| 5 | 50 |
| 9 | 90 |
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
+----+------+
6 rows in set (0.00 sec)
内连接:
mysql> SELECT * FROM tb1 JOIN tb2 ;
+----+------+----+------+
| id | num | id | num |
+----+------+----+------+
| 6 | 60 | 4 | 40 |
| 7 | 70 | 4 | 40 |
| 8 | 80 | 4 | 40 |
| 1 | 1 | 4 | 40 |
| 2 | 2 | 4 | 40 |
| 3 | 3 | 4 | 40 |
| 6 | 60 | 5 | 50 |
| 7 | 70 | 5 | 50 |
| 8 | 80 | 5 | 50 |
.......more......
return 36 rows in set (0.01 sec)
AND NATURAL JOIN :
mysql> SELECT * FROM tb1 NATURAL JOIN tb2 ;
+----+------+
| id | num |
+----+------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
+----+------+
3 rows in set (0.01 sec)
【讨论】:
【参考方案11】:内连接,连接两个列名相同的表。
自然连接,连接两个列名和数据类型相同的表。
【讨论】:
这是完全错误的。NATURAL JOIN
(正如几年前有人指出的那样)是列名相同的列名。数据类型不必相同。用于INNER JOIN
的字段不必具有相同的名称。以上是关于自然连接和内连接的区别的主要内容,如果未能解决你的问题,请参考以下文章