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

smi*_*ith 186 sql join natural-join

自然连接和内连接有什么区别?

Jon*_*ler 231

INNER JOIN和NATURAL JOIN之间的一个显着区别是返回的列数.

考虑:

TableA                           TableB
+------------+----------+        +--------------------+    
|Column1     | Column2  |        |Column1  |  Column3 |
+-----------------------+        +--------------------+
| 1          |  2       |        | 1       |   3      |
+------------+----------+        +---------+----------+
Run Code Online (Sandbox Code Playgroud)

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;
Run Code Online (Sandbox Code Playgroud)

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

+------------+-----------+---------------------+    
| a.Column1  | a.Column2 | b.Column1| b.Column3|
+------------------------+---------------------+
| 1          |  2        | 1        |   3      |
+------------+-----------+----------+----------+
Run Code Online (Sandbox Code Playgroud)

避免重复的列.

(来自标准语法的AFAICT,您不能在自然连接中指定连接列;连接是严格基于名称的.另请参阅维基百科.)

(有一个在内部备忘联接输出;在a.b.部分将不会在列名,你只是有column1,column2,column1,column3作为标题.)

  • 这在user166390的答案中有所解决.假设您在`Customers`和`Employees`之间有一个自然的联接,加入`EmployeeID`.`Employees`也有一个`ManagerID`字段.一切安好.然后,有一天,有人在`Customers`表中添加了一个`ManagerID`字段.你的连接不会破坏(这将是一个怜悯),而是它现在将包括第二个字段,并且工作*不正确*.因此,看似无害的变化可能会破坏与之相关的东西.很坏.自然联接的唯一优势是节省了一点点打字,而且下行空间很大. (34认同)
  • 折叠输出中的列是自然连接中最不重要的方面.你需要知道的事情是(A)它会自动加入同名的字段,(B)它会在你最不期望的时候提升你的s***.在我的世界里,使用自然联合是解雇的理由. (14认同)
  • @JonofAllTrades你能解释更多关于`NATURAL JOIN`究竟会毁了什么,为什么会出乎意料,以及你所处的世界? (8认同)
  • 我有两个表TableA(Column1,Column2)和TableB(Column2,Column3)。 (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列。 (2认同)
  • 我认为内部连接不会给您两次外键列。我测试了,那不是我得到的。实际上,它仅显示一次。 (2认同)

Boh*_*ian 79

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

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

  • 不是标准的sql [SQL 92] 因此不可移植,不是特别可读(大多数SQL编码器)并且可能不受各种工具/库的支持
  • 没有信息; 如果不参考架构,你无法分辨哪些列被加入
  • 您的连接条件非常容易受到架构更改的影响 - 如果有多个自然连接列并且从表中删除了一个此类列,则查询仍将执行,但可能不正确,并且此行为更改将保持静默
  • 几乎不值得努力; 你只需要节省大约10秒的打字时间

  • 我认为应该提到外部的左/右(因为外部被提及).但除此之外,简洁明了:它只缺少漂亮的示例SQL记录图. (2认同)
  • 自然左和自然权利也存在.但是,仍然可以避免它们. (2认同)
  • @sqlvovel你的评论有很多错误,特别是它不正确.加入列**不能"在选择列表中指定".自然连接的定义是*加入*all*like-named列*.来自MySQL doc:*两个表的NATURAL [LEFT] JOIN被定义为在语义上等同于INNER JOIN或LEFT JOIN,其中USING子句命名两个表中存在的所有列.*.另一件事 - 在实践中它是无用的,因为`id`无处不在,无用于加入; 通常的外键名是`tablename_id`.自然联合是一个坏,坏,坏主意. (2认同)
  • 我的查询中没有双返回列.NJ语义的一个优点是永远不会返回重复的列.您之前的查询也比我的查询"安全",因为如果将一个名为"a"的列添加到t2(因为非别名连接条件不明确),它将失败.我怀疑你对NJ的偏见是基于你没有在标准SQL得到适当支持的产品中尝试过它.这里的问题是关于SQL,而不是MySQL - 完全不同的东西.你仍然没有纠正你的答案,因为它是非标准的. (2认同)

Mat*_*lie 23

自然连接只是避免键入的快捷方式,假设连接很简单并且匹配相同名称的字段.

SELECT
  *
FROM
  table1
NATURAL JOIN
  table2
    -- implicitly uses `room_number` to join
Run Code Online (Sandbox Code Playgroud)

是相同的...

SELECT
  *
FROM
  table1
INNER JOIN
  table2
    ON table1.room_number = table2.room_number
Run Code Online (Sandbox Code Playgroud)

但是,使用快捷方式格式无法实现的是更复杂的连接...

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)
Run Code Online (Sandbox Code Playgroud)

  • 好的 - 有趣.我问,因为SQL标准似乎不允许这样(但扩展总是可行的). (3认同)
  • @JonathanLeffler - 在MySQL中,当然. (2认同)

one*_*hen 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和projection(SELECT)编写任何内容,但也INNER JOIN可以使用product(CROSS JOIN)和restriction(WHERE)编写任何内容.进一步注意,NATURAL JOIN没有共同列名的表之间将给出相同的结果CROSS JOIN.所以,如果你只对关系结果感兴趣(为什么不关注?!)那么你NATURAL JOIN是唯一需要的连接类型.当然,从语言设计的角度来看,确实是简单的,例如INNER JOIN并且CROSS 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;
Run Code Online (Sandbox Code Playgroud)

**关系自然连接不是等值连接,它是一个投影. - philipxy


小智 8

一个NATURAL连接是一个只是短期的语法具体 INNER加盟-或"相等连接" -而且,一旦语法是解开,既代表相同的关系代数操作.与OUTER(LEFT/ RIGHT)或CROSS连接的情况一样,它不是一种"不同类型"的连接.

请参阅维基百科上的equi-join部分:

自然连接提供了equi-joins的进一步专业化.通过比较两个表中在连接表中具有相同列名的所有列,隐式地产生连接谓词.生成的连接表仅包含每对同名列的一列.

大多数专家都认为NATURAL JOIN很危险,因此强烈反对使用它们.危险来自无意中添加一个新列,名称与另一列相同......

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

快乐的编码.


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

  • "NATURAL连接只是[snipped]"equi-join"的简短语法 - 而且,一旦语法被解开,两者都代表相同的关系代数" - 你是对的:关系代数也是如此,但你的答案有所破坏之后,例如"大多数专家都认为自然连接是危险的,因此强烈反对使用它们" - 关系代数专家说过这个?! (2认同)