关于sql:自然连接和内连接之间的区别

Difference between natural join and inner join

自然联接和内部联接有什么区别?


内部联接和自然联接之间的一个显著区别是返回的列数。

考虑:

1
2
3
4
5
6
TableA                           TableB
+------------+----------+        +--------------------+    
|Column1     | Column2  |        |Column1  |  Column3 |
+-----------------------+        +--------------------+
| 1          |  2       |        | 1       |   3      |
+------------+----------+        +---------+----------+

第1列的表A和表B的INNER JOIN将返回

1
2
3
4
5
6
7
SELECT * FROM TableA INNER JOIN TableB USING (Column1);
SELECT * FROM TableA INNER JOIN TableB ON TableA.Column1 = TableB.Column1;
+------------+-----------+---------------------+    
| a.Column1  | a.Column2 | b.Column1| b.Column3|
+------------------------+---------------------+
| 1          |  2        | 1        |   3      |
+------------+-----------+----------+----------+

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

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

避免重复列。

(与标准语法不同,不能在自然联接中指定联接列;联接严格基于名称。另见维基百科。)

(内部连接输出中有一个欺骗;a.b.部分不在列名称中;您只需要将column1column2column1column3作为标题。)


  • 内部联接是指需要联接表中的匹配行才能返回第一个表中的行的联接。
  • 外部联接是这样的一种联接:对于要返回的第一个表中的行,不需要联接表中的匹配行。
  • 自然联接是一个联接(可以是natural leftnatural right,它假定联接条件是两个表中相同命名列匹配的地方。

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

  • notstandard sqlandbecause notportable,not specifically readable(by most sql coders)and maybly not supported by various tools/libraries
  • 不具信息性;如果不引用架构,就无法判断哪些列正在被联接。
  • 您的联接条件在不可见的情况下容易受到架构更改的影响-如果存在多个自然联接列,并且从表中删除了一个这样的列,则查询仍将执行,但可能不正确,并且此行为更改将保持沉默。
  • 不值得这么努力;你只节省了大约10秒钟的打字时间


自然联接只是避免键入的快捷方式,假定联接很简单,并且与同名字段匹配。

1
2
3
4
5
6
7
SELECT
  *
FROM
  table1
NATURAL JOIN
  table2
    -- implicitly uses `room_number` to join

与……相同。

1
2
3
4
5
6
7
SELECT
  *
FROM
  table1
INNER JOIN
  table2
    ON table1.room_number = table2.room_number

但是,使用快捷方式格式不能做的是更复杂的连接…

1
2
3
4
5
6
7
8
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)


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

在SQL中,NATURAL JOIN背后的思想是使它更容易对关系模型更加忠实。两个表的NATURAL JOIN的结果将按名称消除列的重复,因此没有匿名列。同样,提供UNION CORRESPONDINGEXCEPT CORRESPONDING来解决SQL对传统UNION语法中列顺序的依赖性。

然而,和所有编程技术一样,它要求规程是有用的。成功的NATURAL JOIN的一个要求是一致命名列,因为连接是在同名列上隐含的(在SQL中重命名列的语法是冗长的,但副作用是在基表和VIEWs中命名列时鼓励规范),这是很遗憾的。

注意,一个SQL NATURAL JOIN是一个相等的连接**,但是这并不能限制有用性。考虑一下,如果NATURAL JOIN是SQL中唯一支持的联接类型,那么它仍然是相对完整的。

虽然确实可以使用INNER JOIN和project(SELECT来编写任何NATURAL JOIN,但也确实可以使用product(CROSS JOIN和restriction(WHERE来编写任何INNER JOIN;进一步注意,没有列名的表之间的NATURAL JOIN将产生与edoc相同的结果。X1〔13〕。所以如果你只对关系的结果感兴趣(为什么不呢?!)那么,NATURAL JOIN是您唯一需要的连接类型。当然,从语言设计的角度来看,像INNER JOINCROSS JOIN这样的速记词确实有其价值,但也考虑到几乎任何SQL查询都可以用10种不同的语法编写,但在语义上是等价的,这就是为什么SQL优化器很难开发的原因。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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;

**关系自然联接不是等联接,它是一个投影。-飞利浦赛


NATURAL联接只是特定INNER联接或"equi联接"的简短语法,一旦语法展开,这两个联接都表示相同的关系代数操作。它不是一种"不同类型"的连接,比如OUTER(LEFT/RIGHT)或CROSS连接。

参见维基百科上的Equi Join部分:

A natural join offers a further specialization of equi-joins. The join predicate arises implicitly by comparing all columns in both tables that have the same column-names in the joined tables. The resulting joined table contains only one column for each pair of equally-named columns.

Most experts agree that NATURAL JOINs are dangerous and therefore strongly discourage their use. The danger comes from inadvertently adding a new column, named the same as another column ...

也就是说,所有的NATURAL联接都可以写成INNER联接(但反过来不是真的)。要做到这一点,只需显式地创建谓词——例如USINGON——并且,正如jonathan leffler指出的那样,选择所需的结果集列,以避免在需要时出现"重复"。

快乐编码。

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


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

内部联接:除非两个表中的任何列名称都是sname,否则此联接将工作。


自然联接是指在所有公共列的基础上联接两个表。

公共列:两个表中名称相同的列+两个表中的数据类型兼容。只能使用=运算符

内部联接是指两个表在ON子句中提到的公共列的基础上进行联接。

公共列:是一个列,它在两个表中都具有兼容的数据类型,但不必具有相同的名称。您只能使用任何比较运算符,如=<=>=<><>


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


不同的是,int内部(equi/default)联接和自然联接(natural join common column win)将一次性显示,而内部/equi/default/simple join公共列将显示两次。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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)

内部连接:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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)

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

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