Mysql表连接:内连接、外连接、交叉连接、自然连接真的都不一样吗
文章目录
- 前言
- 测试环境
- 创建测试数据
- 对比测试
- 内连接
- 交叉连接
- 外连接
- 左外连接
- 右外连接
- 自然连接
- 一般自然连接
- 自然左外连接
- 自然右外连接
- STRAIGHT_JOIN
- 逗号分隔连接表
- 各种连接对比
- 总结
前言
提起这几种表连接方式就让人头大,想当初还因为这个面试被刷了,长得挺像,用法挺像,可就是有点不一样,其实的它们的差异不是固定的,要在一个具体的环境下才能进行对比,比如在Mysql环境下, JOIN, INNER JOIN, CROSS JOIN
三者在语法上是等价的,也就是作用相同,但是在标准的SQL下却又存在差异。
选一个自己熟悉的环境对比一下,那就是Mysql数据库的表连接了,测试的多了渐渐的发现了一些规律和神坑,貌似一切表连接都是以内连接为基础,然后再此基础上进行变换可以得到一种新的连接,接下来就采用这种对比的逻辑,看看这些连接类型都有什么区别和联系。
测试环境
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 5.7.21-log MySQL Community Server (GPL)
Copyright © 2000, 2018, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners.
创建测试数据
- 新建第一个测试表格
a
,包含id和name两列
create table a(id int, name varchar(64), primary key(id));
- 插入测试数据
insert into a values(1, 'albert');
insert into a values(2, 'bella');
insert into a values(3, 'amy');
insert into a values(4, 'forier');
- 新建第二个测试表格
b
,包含id和age两列
create table b(id int, age int, primary key(id));
- 插入测试数据
insert into b values(1, 18);
insert into b values(2, 19);
insert into b values(3, 25);
insert into b values(5, 70);
- 分别查看两表中的数据如下
mysql> select * from a;
+----+--------+
| id | name |
+----+--------+
| 1 | albert |
| 2 | bella |
| 3 | amy |
| 4 | forier |
+----+--------+
4 rows in set (0.04 sec)mysql> select * from b;
+----+-----+
| id | age |
+----+-----+
| 1 | 18 |
| 2 | 19 |
| 3 | 25 |
| 5 | 70 |
+----+-----+
4 rows in set (0.05 sec)
对比测试
这篇对比文章可能和以往你看到的不太一样,对比的基础是内连接,其他的连接基本可以看做是在内连接的基础上加了一些条件和扩展得到的,所以首先我们需要先来看一下内连接。
内连接
内连接基础语法是a inner join b
,不过其中的inner
可以省略,也就是可以写成a join b
,如果不添加条件就是a表中的每条记录分别与b表中的每条记录做匹配,形成笛卡尔积,查询结果如下:
mysql> select * from a inner join b;
+----+--------+----+-----+
| id | name | id | age |
+----+--------+----+-----+
| 1 | albert | 1 | 18 |
| 2 | bella | 1 | 18 |
| 3 | amy | 1 | 18 |
| 4 | forier | 1 | 18 |
| 1 | albert | 2 | 19 |
| 2 | bella | 2 | 19 |
| 3 | amy | 2 | 19 |
| 4 | forier | 2 | 19 |
| 1 | albert | 3 | 25 |
| 2 | bella | 3 | 25 |
| 3 | amy | 3 | 25 |
| 4 | forier | 3 | 25 |
| 1 | albert | 5 | 70 |
| 2 | bella | 5 | 70 |
| 3 | amy | 5 | 70 |
| 4 | forier | 5 | 70 |
+----+--------+----+-----+
16 rows in set (0.03 sec)mysql> select * from a join b;
+----+--------+----+-----+
| id | name | id | age |
+----+--------+----+-----+
| 1 | albert | 1 | 18 |
| 2 | bella | 1 | 18 |
| 3 | amy | 1 | 18 |
| 4 | forier | 1 | 18 |
| 1 | albert | 2 | 19 |
| 2 | bella | 2 | 19 |
| 3 | amy | 2 | 19 |
| 4 | forier | 2 | 19 |
| 1 | albert | 3 | 25 |
| 2 | bella | 3 | 25 |
| 3 | amy | 3 | 25 |
| 4 | forier | 3 | 25 |
| 1 | albert | 5 | 70 |
| 2 | bella | 5 | 70 |
| 3 | amy | 5 | 70 |
| 4 | forier | 5 | 70 |
+----+--------+----+-----+
16 rows in set (0.04 sec)
需要注意的是内连接的连接条件是可选择,如果不加就是笛卡尔积,如果想加的话可以选择on
子句或者using
子句,比如需要得到a表与b表中id一致的数据记录就可以使用如下on
子句的写法:
mysql> select * from a join b on a.id = b.id;
+----+--------+----+-----+
| id | name | id | age |
+----+--------+----+-----+
| 1 | albert | 1 | 18 |
| 2 | bella | 2 | 19 |
| 3 | amy | 3 | 25 |
+----+--------+----+-----+
3 rows in set (0.04 sec)
同时对于上述例子中这个on
子句中是被连接的两表的同时存在的字段时,可以使用using
子句简化,写成如下查询,需要注意下结果集的变化,记录的条数与on
子句相同,但是共有的id列被优化掉了一个,这也是on
和using
子句的区别,使用时根据需要选择:
mysql> select * from a join b using(id);
+----+--------+-----+
| id | name | age |
+----+--------+-----+
| 1 | albert | 18 |
| 2 | bella | 19 |
| 3 | amy | 25 |
+----+--------+-----+
3 rows in set (0.04 sec)
交叉连接
交叉连接基础语法是a cross join b
,在Mysql的语法环境中,内连接与交叉连接完全一致,这一点可以通过下面几条查询与内连接的查询做对比得知:
mysql> select * from a cross join b;
+----+--------+----+-----+
| id | name | id | age |
+----+--------+----+-----+
| 1 | albert | 1 | 18 |
| 2 | bella | 1 | 18 |
| 3 | amy | 1 | 18 |
| 4 | forier | 1 | 18 |
| 1 | albert | 2 | 19 |
| 2 | bella | 2 | 19 |
| 3 | amy | 2 | 19 |
| 4 | forier | 2 | 19 |
| 1 | albert | 3 | 25 |
| 2 | bella | 3 | 25 |
| 3 | amy | 3 | 25 |
| 4 | forier | 3 | 25 |
| 1 | albert | 5 | 70 |
| 2 | bella | 5 | 70 |
| 3 | amy | 5 | 70 |
| 4 | forier | 5 | 70 |
+----+--------+----+-----+
16 rows in set (0.04 sec)mysql> select * from a cross join b on a.id = b.id;
+----+--------+----+-----+
| id | name | id | age |
+----+--------+----+-----+
| 1 | albert | 1 | 18 |
| 2 | bella | 2 | 19 |
| 3 | amy | 3 | 25 |
+----+--------+----+-----+
3 rows in set (0.04 sec)mysql> select * from a cross join b using(id);
+----+--------+-----+
| id | name | age |
+----+--------+-----+
| 1 | albert | 18 |
| 2 | bella | 19 |
| 3 | amy | 25 |
+----+--------+-----+
3 rows in set (0.04 sec)
外连接
在Mysql中外连接分为左外连接和右外连接,但不存在全外连接,这一点与Oracle有些不同,不过可以通过左外连接和右外连接合并出全外连接的结果集,需要注意的是外连接必须添加on
子句或者using
子句,否则会报语法错误,对于左、有外连接可以分别看一下:
左外连接
左外连接基础语法是a left outer join b
,其中的outer
可以省略,与内连接相比就是在与内连接相同条件下,在内连接的结果集中添加a表在b表中找不到匹配的记录,换句话说就是,结果集中会包含a表中的所有记录,如果b表中有匹配的记录就出现在结果集,否则使用NULL
代替,也就是把a表看成根本,不可缺失记录,查询结果如下:
mysql> select * from a left outer join b on a.id = b.id;
+----+--------+------+------+
| id | name | id | age |
+----+--------+------+------+
| 1 | albert | 1 | 18 |
| 2 | bella | 2 | 19 |
| 3 | amy | 3 | 25 |
| 4 | forier | NULL | NULL |
+----+--------+------+------+
4 rows in set (0.04 sec)mysql> select * from a left join b on a.id = b.id;
+----+--------+------+------+
| id | name | id | age |
+----+--------+------+------+
| 1 | albert | 1 | 18 |
| 2 | bella | 2 | 19 |
| 3 | amy | 3 | 25 |
| 4 | forier | NULL | NULL |
+----+--------+------+------+
4 rows in set (0.03 sec)
这个左外连接查询同样可以使用using
子句来化简,并且也会将共有的字段省略一个:
mysql> select * from a left join b using(id);
+----+--------+------+
| id | name | age |
+----+--------+------+
| 1 | albert | 18 |
| 2 | bella | 19 |
| 3 | amy | 25 |
| 4 | forier | NULL |
+----+--------+------+
4 rows in set (0.04 sec)
右外连接
右外连接基础语法是a right outer join b
,其中的outer
可以省略,与内连接相比就是在与内连接相同条件下,在内连接的结果集中添加b表在a表中找不到匹配的记录,换句话说就是,结果集中会包含b表中的所有记录,如果a表中有匹配的记录就出现在结果集,否则使用NULL
代替,也就是把b表看成根本,不可缺失记录,作用与左外连接恰好相反,查询结果如下:
mysql> select * from a right outer join b on a.id = b.id;
+------+--------+----+-----+
| id | name | id | age |
+------+--------+----+-----+
| 1 | albert | 1 | 18 |
| 2 | bella | 2 | 19 |
| 3 | amy | 3 | 25 |
| NULL | NULL | 5 | 70 |
+------+--------+----+-----+
4 rows in set (0.03 sec)mysql> select * from a right join b on a.id = b.id;
+------+--------+----+-----+
| id | name | id | age |
+------+--------+----+-----+
| 1 | albert | 1 | 18 |
| 2 | bella | 2 | 19 |
| 3 | amy | 3 | 25 |
| NULL | NULL | 5 | 70 |
+------+--------+----+-----+
4 rows in set (0.04 sec)mysql> select * from a right join b using(id);
+----+-----+--------+
| id | age | name |
+----+-----+--------+
| 1 | 18 | albert |
| 2 | 19 | bella |
| 3 | 25 | amy |
| 5 | 70 | NULL |
+----+-----+--------+
4 rows in set (0.04 sec)
自然连接
自然连接从名字来看就是两个表很自然的就连接上了,这要求两个表需要有可以参照的数据,具体到表设计上就是要求两个表必须要有相同的列,需要注意的是自然连接不允许添加连接子句,否则会报语法错误。自然连接分为一般自然连接、左外连接和自然右外连接连接,还是以内连接为标准,看看自然连接有什么不同:
一般自然连接
一般自然连接基础语法是a natural join b
,它不能加连接条件,使用两个表共有的字段id来“自然”地链接,同时会省略共有的字段,其作用相同于内连接使用using
子句来查询,通过下面的对比,你会发现他们的作用是一样的。
mysql> select * from a natural join b;
+----+--------+-----+
| id | name | age |
+----+--------+-----+
| 1 | albert | 18 |
| 2 | bella | 19 |
| 3 | amy | 25 |
+----+--------+-----+
3 rows in set (0.03 sec)mysql> select * from a join b using(id);
+----+--------+-----+
| id | name | age |
+----+--------+-----+
| 1 | albert | 18 |
| 2 | bella | 19 |
| 3 | amy | 25 |
+----+--------+-----+
3 rows in set (0.04 sec)
自然左外连接
自然左外连接基础语法是a natural left outer join b
,其中的outer
可以省略,它也不能加连接条件,使用两个表共有的字段id来“自然”地链接,同时会省略共有的字段,其作用相同于内连接使用using
子句同时包含a表中的所有记录,以a表作为根本,包含所有记录,并且显示b表中匹配记录,如没有与a表匹配的记录则以NULL
代替,其实就是左外连接省略掉using
子句:
mysql> select * from a natural left outer join b;
+----+--------+------+
| id | name | age |
+----+--------+------+
| 1 | albert | 18 |
| 2 | bella | 19 |
| 3 | amy | 25 |
| 4 | forier | NULL |
+----+--------+------+
4 rows in set (0.04 sec)mysql> select * from a natural left join b;
+----+--------+------+
| id | name | age |
+----+--------+------+
| 1 | albert | 18 |
| 2 | bella | 19 |
| 3 | amy | 25 |
| 4 | forier | NULL |
+----+--------+------+
4 rows in set (0.03 sec)mysql> select * from a left join b using(id);
+----+--------+------+
| id | name | age |
+----+--------+------+
| 1 | albert | 18 |
| 2 | bella | 19 |
| 3 | amy | 25 |
| 4 | forier | NULL |
+----+--------+------+
4 rows in set (0.03 sec)
自然右外连接
自然左外连接基础语法是a natural right outer join b
,其中的outer
可以省略,它也不能加连接条件,其作用与自然左外连接相反,其实就是右外连接省略掉using
子句:
mysql> select * from a natural right outer join b;
+----+-----+--------+
| id | age | name |
+----+-----+--------+
| 1 | 18 | albert |
| 2 | 19 | bella |
| 3 | 25 | amy |
| 5 | 70 | NULL |
+----+-----+--------+
4 rows in set (0.04 sec)mysql> select * from a natural right join b;
+----+-----+--------+
| id | age | name |
+----+-----+--------+
| 1 | 18 | albert |
| 2 | 19 | bella |
| 3 | 25 | amy |
| 5 | 70 | NULL |
+----+-----+--------+
4 rows in set (0.04 sec)mysql> select * from a right join b using(id);
+----+-----+--------+
| id | age | name |
+----+-----+--------+
| 1 | 18 | albert |
| 2 | 19 | bella |
| 3 | 25 | amy |
| 5 | 70 | NULL |
+----+-----+--------+
4 rows in set (0.04 sec)
STRAIGHT_JOIN
STRAIGHT_JOIN
的基础语法是a STRAIGHT_JOIN b
,确实没有找到这种连接的中文说法,不过它与内连接几乎一样,只是它总是把左侧a表作为驱动表优先读入,它只能加on
子句,无法使用using
子句,在Sql优化的过程中常常使用,也就是拒绝了Mysql的语句优化,而使用自己指定的顺序来连接表格,不过使用时需慎重,你得比Mysql聪明才可以!
mysql> select * from a straight_join b on a.id = b.id;
+----+--------+----+-----+
| id | name | id | age |
+----+--------+----+-----+
| 1 | albert | 1 | 18 |
| 2 | bella | 2 | 19 |
| 3 | amy | 3 | 25 |
+----+--------+----+-----+
3 rows in set (0.04 sec)
逗号分隔连接表
在from
之后用逗号分隔的两个表格像极了内连接,只不过用逗号分隔的表不能使用子句连接,只可以用where
来做条件筛选,不过作用之后的结果是一致的,可以对比看一下:
mysql> select * from a join b on a.id = b.id;
+----+--------+----+-----+
| id | name | id | age |
+----+--------+----+-----+
| 1 | albert | 1 | 18 |
| 2 | bella | 2 | 19 |
| 3 | amy | 3 | 25 |
+----+--------+----+-----+
3 rows in set (0.04 sec)mysql> select * from a, b where a.id = b.id;
+----+--------+----+-----+
| id | name | id | age |
+----+--------+----+-----+
| 1 | albert | 1 | 18 |
| 2 | bella | 2 | 19 |
| 3 | amy | 3 | 25 |
+----+--------+----+-----+
3 rows in set (0.04 sec)
各种连接对比
通过描述可能有些关系还是没理解太清楚,所以整理了下面的表格,对比的更清楚一点,其中[]
中的内容在编写sql时可以省略:
连接类型 | 语法 | 不加条件 |
加ON 子句
|
加USING 子句
|
与内连接关系 |
---|---|---|---|---|---|
内连接 |
a [INNER] JOIN b
|
两表中任意两条记录分别匹配,形成笛卡尔积 | 只按照条件匹配,所有列均显示 | 按照共有的列匹配,去除重复列 | X |
交叉连接 |
a [CROSS] JOIN b
|
两表中任意两条记录分别匹配,形成笛卡尔积 | 只按照条件匹配,所有列均显示 | 按照共有的列匹配,去除重复列 | 语法等价,完全相同 |
左外连接 |
a LEFT [OUTER] JOIN b
|
必须加条件,否则报语法错误 | 只按照条件匹配,并且包含a表中没有匹配上的记录 | 按照共有的列匹配,并且包含a表中没有匹配上的记录 | 额外包含a表中没有匹配上的记录 |
右外连接 |
a RIGHT [OUTER] JOIN b
|
必须加条件,否则报语法错误 | 只按照条件匹配,并且包含b表中没有匹配上的记录 | 按照共有的列匹配,并且包含b表中没有匹配上的记录 | 额外包含b表中没有匹配上的记录 |
一般自然连接 |
a NATURAL JOIN b
|
使用两表中共有的字段匹配 |
不能使用ON 子句
|
不能使用USING 子句
|
相当于内连接使用USING子句 |
自然左外连接 |
a NATURAL LEFT [OUTER] JOIN b
|
使用两表中共有的字段匹配,并且包含a表中没有匹配上的记录 |
不能使用ON 子句
|
不能使用USING 子句
|
相当于内连接使用USING子句,并且包含a表中没有匹配上的记录 |
自然右外连接 |
a NATURAL RIGHT [OUTER] JOIN b
|
使用两表中共有的字段匹配,并且包含b表中没有匹配上的记录 |
不能使用ON 子句
|
不能使用USING 子句
|
相当于内连接使用USING子句,并且包含b表中没有匹配上的记录 |
STRAIGHT_JOIN |
a STRAIGHT_JOIN b
|
两表中任意两条记录分别匹配,形成笛卡尔积 | 只按照条件匹配,所有列均显示 |
不能使用USING 子句
|
在内连接基础上确定读表顺序 |
逗号分隔表 |
a, b
|
两表中任意两条记录分别匹配,形成笛卡尔积 |
不能使用ON 子句
|
不能使用USING 子句
|
不能使用连接子句,只能使用Where 筛选
|
总结
- 总的来看外连接中的
outer
是最没有存在感的,凡是它出现的地方都可以省略 - 黑魔法:
a inner join b
与a cross join b
是等价的,后来我偶然间拼写错误发现a across join b
也是可以的,另外a love join b
也行,开始还以为发现了bug,后来再理解应该是拼错的单词作了表a的别名,虚惊一场! - 通过上面的表格发现每种连接貌似都和内连接扯上了关系,那就以内连接为基础,通过扩展来记忆也是不错的
- 如果表格不够清晰,换成思维导图或许会更好一些
Mysql表连接:内连接、外连接、交叉连接、自然连接真的都不一样吗相关推荐
- mysql 笛卡尔积_Mysql(笛卡尔积、等值连接、自然连接、外连接)
1.笛卡尔积 笛卡尔积的元素是元组,关系A和B的笛卡尔积可以记为(AXB),如果A为a目,B为b目,那么A和B的笛卡尔积为(a+b)列.(a*b)行的元组集合. (1)学生表和分数表中的信息: 学生表 ...
- 内连接、外链接、自然连接、全连接
oracle sql的连接类型有: 内连接(inner join也叫join) 外链接:分为 左连接left join . 右连接right join 自然连接:natrue join.特点:连接后的 ...
- mysql内联表格使用索引_【求助】MYSQL表关联内联视图不走索引问题??诡异啊...
首先声明: FACT_DATE_SALES_CI_INDEX 的DAY,DIM_ORG建有复合索引,同时FACT_DATE_SALES_FACT_DATE_SALES_F1表的RETAIL_SALES ...
- MySQL—表的完整性约束(外键约束)(一)
1.什么是完整性约束? 为防止不符合规范的数据存入数据库,在用户对数据进行插入.修改.删除等操作时,MySQL提供了一种机制来检查数据库中的数据是否满足规定的条件,以保证数据库中数据的准确性和一致性, ...
- MySQL—表的完整性约束(外键约束)(二)
1.班级表 2.学生表 例1:删除班级5:如果直接删除的话肯定不行,因为有外键约束 delete from t_class where cno=5; 1451 - Cannot delete or u ...
- autojs定时可以选定日期吗_Excel工作表中的7个“一键完成”,你真的都了解、掌握吗?...
在Excel工作表中,部分比较复杂的功能其实可以"一键完成",但实际应用率并不高,结合工作实际,小编总结了7个"一键完成",希望对各位亲的工作效率有所帮助哦! ...
- 数据库——自然连接、内连接、外连接(左外连接、右外连接、全外连接)、交叉连接
1. 自然连接(*natural join)* 自然连接不用指定连接列,也不能使用ON语句,它默认比较两张表里相同的列, `SELECT*FROM student NATURAL JOIN score ...
- 连接查询(交叉连接,内连接,外连接,自然连接)
创建一个学生表和一个课程表.先放出实验的表结构: create table student( id int, name varchar(15), gender varchar(15), cid int ...
- MySQL 表关系及多表操作(联合查询、连接查询、子查询)
文章目录 表关系 一对一关系 一对多关系 多对多关系 总结 MySQL多表操作 联合查询 联合查询排序 连接查询 交叉连接 内连接 外连接 自然连接 using关键字 子查询 表关系 表关系:一个表代 ...
最新文章
- IE浏览器中iframe背景BODY透明
- DVWA通关教程(中)
- BZOJ.2780.[SPOJ8093]Sevenk Love Oimaster(广义后缀自动机)
- linux数组随机数,随机数与数组
- mysql数据库操作宠物表_mysql数据库之表的操作
- (08)Verilog HDL同步复位
- 【Linux】Linux使用sar进行性能分析
- 《移动通信原理与系统》——第二章《移动通信电波传播与传播预测模型》——笔记
- java 视频上传_java实现大视频上传
- “微信之父”张小龙:微信背后的产品观
- 【作业】【2.3标识符及其命名】
- 实验6 - 家中的电视
- RFID天线技术 – 低频和高频RFID天线设计
- Linux服务器之Samba匿名访问配置
- 主机/虚拟机/开发板三者互通
- 简述计算机蓝屏的主要原因,常见电脑蓝屏的原因有什么
- 如何安装Win10与Ubuntu16.04.5LTS
- ecstore安装 mysql_GitHub - shopex/docker-ecstore: ecstore的官方docker镜像
- 从实际案例,看视频信息化在教育行业的应用现状
- 软件开发管理中的博奕论
热门文章
- javaScript-模块化开发
- goahead解析(一)---------route.txt
- Direct3D 12 尝鲜(五): SDK 更新
- Android 搭建Linux服务器
- Realtek WiFi concurrent 模式介绍
- 02.微软官方启动U盘装机教程
- WPF之布局属性HorizontalAlignment、HorizontalContentAlignment、VertialAlignment、VerticalContentAlignment
- transform三大属性之scale(缩放)
- 高级计算机维修员职业资格证书,关于国家高级计算机维修职业资格证书在太原市怎么..._出版资格_帮考网...
- 【单片机笔记】详解如何用廉价NTC电阻准确高效的测量温度(附源码)