自然连接和内部连接之间的区别


Answers:


250

INNER JOIN和NATURAL JOIN之间的一个重要区别是返回的列数。

考虑:

TableA                           TableB
+------------+----------+        +--------------------+    
|Column1     | Column2  |        |Column1  |  Column3 |
+-----------------------+        +--------------------+
| 1          |  2       |        | 1       |   3      |
+------------+----------+        +---------+----------+

INNER JOIN表A和表B对列1将返回

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      |
+------------+-----------+----------+----------+

NATURAL JOIN表A和表B在列1将返回:

SELECT * FROM TableA NATURAL JOIN TableB
+------------+----------+----------+    
|Column1     | Column2  | Column3  |
+-----------------------+----------+
| 1          |  2       |   3      |
+------------+----------+----------+

避免重复的列。

(根据标准语法的AFAICT,您不能在自然连接中指定连接列;该连接严格基于名称。另请参见Wikipedia。)

有一个在内部备忘加入输出;在a.b.部分将不会在列名,你只是有column1column2column1column3作为标题。


2
我有两个表TableA(Column1,Column2)和TableB(Column2,Column3)。
2 8 8

16
输出中的折叠列是自然连接的最不重要的方面。您需要知道的是(A)它会自动在相同名称的字段上联接,并且(B)在您最不希望它出现时,它会使您的***崩溃。在我的世界中,使用自然加入是解雇的理由。

8
@JonofAllTrades您能详细解释一下什么NATURAL JOIN将毁灭,为什么会出乎意料以及您所处的世界吗?
布赖森2014年

35
这在user166390的答案中有所解决。假设您Customers与之间自然相连Employees,然后继续EmployeeIDEmployees也有一个ManagerID领域。一切安好。然后,有一天,有人将一个ManagerID字段添加到Customers表中。您的加入不会中断(这将是一个怜悯),相反,它现在将包括第二个字段,并且工作不正确。因此,看似无害的变化可能会破坏远距离相关的事物。很坏。自然连接的唯一好处是节省了一些键入操作,而且缺点很大。

2
@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列。
Pacerier

81
  • 一个内在的连接是一个其中需要对于行从第一表中联接表中的匹配的行要被返回
  • 一个连接是一个在地方连接表的匹配行所需的行从第一表被返回
  • 一个自然的联接是联接(你可以有natural leftnatural right),它假定连接标准是其中两个表匹配的同名列

我会避免使用像瘟疫这样的自然联接,因为自然联接是:

  • 不是标准sql [SQL 92],因此不可移植,不是特别易读(大多数SQL编码人员),并且可能不受各种工具/库的支持
  • 没有信息 您不能不参考架构就知道要连接的列
  • 您的联接条件显然不容易受到架构更改的影响-如果有多个自然联接列,并且从表中删除了一个这样的列,查询仍将执行,但可能无法正确执行,并且这种行为更改将保持沉默
  • 几乎不值得付出努力;您只节省了大约10秒钟的打字时间

2
我认为应该提到外部的左/右(因为根本提到外部)。但除此之外,简洁明了:它只缺少漂亮的示例SQL记录图。

2
还存在“自然左”和“自然右”。但是,是的,仍然避免使用它们。
MatBailie'1

1
@Bohemian,关于“避免它们像瘟疫一样”,存在自然连接的实际用例,它们可以派上用场。mariadb.com/kb/zh-cn/sql-99/natural-join “ ... NATURAL JOIN Checkouts只有在正式且强制执行数据库命名约定时,才可能使用看起来随意的” Books “。”
Pacerier 2015年

2
@sqlvovel您的评论有很多错误,特别是它是错误的。联接列不能 “在选择列表中指定”。自然联接的定义是在*所有类似名称的列*上联接。从MySQL doc:两个表的NATURAL [LEFT] JOIN定义为在语义上等效于INNER JOIN或带有USING子句的LEFT JOIN,该子句命名两个表中都存在的所有列。。另一件事-在实践中它是无用的,因为id它无处不在且无用。通常的外键名称是tablename_id。自然连接是一个坏,坏,坏的主意。
波希米亚

2
我的查询中没有双返回列。NJ语义的优点之一是,绝不会返回重复的列。您之前的查询也比我的查询“不安全”,因为如果在t2中添加了名为“ a”的列,则查询将失败(因为非混叠联接条件不明确)。我怀疑您对NJ的偏见是基于您尚未在适当支持标准SQL的产品中尝试过的事实。这里的问题是关于SQL,而不是MySQL-完全不同。您仍然没有更正关于非标准答案的答案。
nvogel

27

自然联接只是避免键入的捷径,前提是联接很简单并且匹配具有相同名称的字段。

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)

2
@JonathanLeffler-当然在MySQL中。
MatBailie 2012年

3
好的-很有趣。我问是因为SQL标准似乎不允许这样做(但始终可以进行扩展)。
乔纳森·勒夫勒

这DBMS允许这种不规范的语法:NATURAL JOIN ... USING ()?该标准是任一a NATURAL JOIN ba JOIN b USING (c)
ypercubeᵀᴹ

1
“只是避免输入的捷径”是错误的陈述。它最重要的功能是不会导致重复的列。
一天,

...例如,使用自然room_number联接的查询结果将只有一个名为的列,而内部联接将有两个名为的列room_number
某一天

13

SQL在许多方面都不忠实于关系模型。SQL查询的结果不是关系,因为它可能具有名称重复的列,“匿名”(未命名)列,重复的行,空值等。SQL不会将表视为关系,因为它依赖于列顺序等。

NATURAL JOINSQL 背后的思想是使对关系模型的忠诚更容易。NATURAL JOIN两个表的结果将具有按名称重复删除的列,因此没有匿名列。类似地,提供了UNION CORRESPONDINGEXCEPT CORRESPONDING来解决旧版中SQL对列顺序的依赖。UNION语法。

但是,与所有编程技术一样,它要求纪律有用。成功的一个要求NATURAL JOIN是命名字段的名称始终一致,因为联接隐含在具有相同名称的列上(在SQL中重命名列的语法很冗长,但是副作用是鼓励在基表和列中命名列时的纪律性。VIEWs :)

请注意,SQL NATURAL JOIN是等值连接**,但是这并不意味着实用性。考虑一下,如果这NATURAL JOIN是SQL支持的唯一连接类型,则它仍然是关系完整的

确实NATURAL JOIN可以使用INNER JOIN和投影(SELECT)编写任何内容,但也INNER JOIN可以使用乘积(CROSS JOIN)和限制(WHERE)编写任何内容;进一步注意,NATURAL JOIN没有共同列名的表之间的a 将产生与相同的结果CROSS JOIN。因此,如果您仅对作为关系的结果感兴趣(为什么不这样做?!),那么这NATURAL JOIN是您唯一需要的联接类型。当然,这是事实,从语言设计的角度来看的速记如INNER JOINCROSS JOIN具有它们的价值,但同时也考虑到几乎所有SQL查询都可以用10种语法上不同但在语义上等效的方式来编写,这使SQL优化器非常困难。发展。

以下是一些语义上等效的示例查询(使用普通零件和供应商数据库):

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

@philipxy:谢谢,我已经修正了。请随意编辑-这个或我的任何答案-陈述错误和误解。我仍在向您学习:)
一天,

9

一个NATURAL连接是一个只是短期的语法具体 INNER加盟-或“相等连接” -而且,一旦语法是解开,既代表相同的关系代数操作。与OUTERLEFT/ RIGHT)或CROSSjoin 的情况不同,它不是“不同的” 联接。

请参阅Wikipedia上的参部分:

自然联接提供了对等联接的进一步专业化。通过比较两个表所有在联接表中具有相同列名的列,可以隐式地产生联接谓词。对于每对同名列,结果联接表仅包含一个列。

大多数专家都认为,NATURAL JOIN非常危险,因此强烈建议不要使用它们。危险来自无意中添加了与另一列相同名称的新列...

也就是说,所有NATURAL联接都可以写为INNER联接(但反之则不成立)。为此,只需显式创建谓词 -例如,USINGON,并且正如Jonathan Leffler所指出的那样,选择所需的结果集列,以在需要时避免“重复”。

快乐的编码。


NATURAL关键字也可以应用于LEFTRIGHT联接,同样也适用。联接NATURAL LEFT/RIGHT只是特定 联接的简短语法LEFT/RIGHT。)


2
“ NATURAL join只是[snipped]“ equi-join”的简短语法-一旦语法解开,它们就代表同一个关系代数”-您是正确的:这对关系代数是正确的,但您的答案却不正确之后,例如“大多数专家都认为NATURAL JOIN是危险的,因此强烈反对使用它们”-关系代数中的哪位专家这么说?
一天,2016年

2

自然联接:这是两个表中所有列的组合或组合结果。它将返回第一个表相对于第二个表的所有行。

内部联接:除非两个表中的任何列名都为sxame,否则此联接将起作用


3
我认为您的答案不够清晰,因此需要大量重写才能解决。
13年

0

自然联接是在所有公共列的基础上联接2个表的地方。

common column:是在两个表中具有相同名称的列,并且在两个表中具有兼容的数据类型。您只能使用=运算符

内部联接是在ON子句中提到的公用列的基础上联接2个表的地方。

common column:是在两个表中具有兼容数据类型但不必具有相同名称的列。你可以只使用任何运营商比较像=<=>=<><>


-2

区别在于int内部(equi / default)连接和自然连接在natuarl连接公共列win中将一次显示,而inner / equi / default / simple连接公共列将显示两次。


-2

内连接和自然连接几乎相同,但两者之间略有不同。区别在于自然联接不需要指定条件,而内部联接条件是必须的。如果确实在内部联接中指定条件,则结果表就像笛卡尔积。


为什么无需指定连接条件?在什么情况下,在内部联接中指定条件会导致产生笛卡尔积?
一天,

将外部联接和内部联接称为“几乎相同”是一种轻描淡写的恕我直言..也许您可以详细说明您的评估?
TMOTTM

-3
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)

-4

内部联接,联接列名称相同的两个表。

自然联接,联接两个表,其中列名和数据类型相同。


这是完全不正确的。A NATURAL JOIN(如几年前几个人所指出的)是列名称相同的名称。数据类型不必相同。用于INNER JOIN需求的字段不必具有相同的名称。
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.