MySQL - LEFT JOIN、RIGHT JOIN、INNER JOIN、CROSS JOIN、FULL JOIN

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用系列 2核4GB
简介: MySQL - LEFT JOIN、RIGHT JOIN、INNER JOIN、CROSS JOIN、FULL JOIN

一、Join语法概述

join 用于多表中字段之间的联系,语法如下:

... FROMtable1INNER|LEFT|RIGHTJOINtable2ONconditiona

able1:左表;table2:右表。

JOIN 按照功能大致分为如下三类:

INNER JOIN(内连接或等值连接:取得两个表中存在连接匹配关系的记录。


LEFT JOIN(左连接):取得左表(table1)完全记录,即是右表(table2)并无对应匹配记录。


RIGHT JOIN(右连接):与 LEFT JOIN 相反,取得右表(table2)完全记录,即是左表(table1)并无匹配对应记录。

注意:mysql不支持Full join,不过可以通过UNION 关键字来合并 LEFT JOIN 与 RIGHT JOIN来模拟FULL join.


Ps:我们了解到在 MySQL 中,INNER JOIN...ON,JOIN...ON,逗号...WHERE,CROSS JOIN...ON 是一样的含义。但是在标准 SQL 中,它们并不等价。


当然“逗号...WHERE”和上述的“JOIN”之间底层还是有区别的


JOIN 是生成一张临时表,然后 WHERE 进一步筛选,所以如果在 JOIN 的时候就能筛选掉的话(替 WHERE 分担一些性能开销)那是最好不过了。


接下来给出一个列子用于解释下面几种分类。如下两个表(A,B)

mysql>selectA.id,A.name,B.namefromA,BwhereA.id=B.id;
+----+-----------+-------------+|id|name|name|+----+-----------+-------------+|1|Pirate|Rutabaga||2|Monkey|Pirate||3|Ninja|DarthVader||4|Spaghetti|Ninja|+----+-----------+-------------+4rowsinset (0.00sec)

二、Inner join

内连接,也叫等值连接,inner join产生同时符合A和B的一组数据。

mysql>select*fromAinnerjoinBonA.name=B.name;
+----+--------+----+--------+|id|name|id|name|+----+--------+----+--------+|1|Pirate|2|Pirate||3|Ninja|4|Ninja|+----+--------+----+--------+

image.png


三、Left join

mysql>select*fromAleftjoinBonA.name=B.name;
#或者:select * from A left outer join B on A.name = B.name;+----+-----------+------+--------+|id|name|id|name|+----+-----------+------+--------+|1|Pirate|2|Pirate||2|Monkey|NULL|NULL||3|Ninja|4|Ninja||4|Spaghetti|NULL|NULL|+----+-----------+------+--------+4rowsinset (0.00sec)

left join,(或left outer join:在Mysql中两者等价,推荐使用left join.)左连接从左表(A)产生一套完整的记录,与匹配的记录(右表(B)) .如果没有匹配,右侧将包含null。

image.png

如果想只从左表(A)中产生一套记录,但不包含右表(B)的记录,可以通过设置where语句来执行,如下:

mysql>select*fromAleftjoinBonA.name=B.namewhereA.idisnullorB.idisnull;
+----+-----------+------+------+|id|name|id|name|+----+-----------+------+------+|2|Monkey|NULL|NULL||4|Spaghetti|NULL|NULL|+----+-----------+------+------+2rowsinset (0.00sec)

image.png

同理,还可以模拟inner join. 如下:

mysql>select*fromAleftjoinBonA.name=B.namewhereA.idisnotnullandB.idisnotnull;
+----+--------+------+--------+|id|name|id|name|+----+--------+------+--------+|1|Pirate|2|Pirate||3|Ninja|4|Ninja|+----+--------+------+--------+2rowsinset (0.00sec)

求差集:

根据上面的例子可以求差集,如下:

SELECT*FROMALEFTJOINBONA.name=B.nameWHEREB.idISNULLunionSELECT*FROMArightJOINBONA.name=B.nameWHEREA.idISNULL;
# 结果+------+-----------+------+-------------+|id|name|id|name|+------+-----------+------+-------------+|2|Monkey|NULL|NULL||4|Spaghetti|NULL|NULL||NULL|NULL|1|Rutabaga||NULL|NULL|3|DarthVader|+------+-----------+------+-------------+

image.png


四、Right join

mysql>select*fromArightjoinBonA.name=B.name;
+------+--------+----+-------------+|id|name|id|name|+------+--------+----+-------------+|NULL|NULL|1|Rutabaga||1|Pirate|2|Pirate||NULL|NULL|3|DarthVader||3|Ninja|4|Ninja|+------+--------+----+-------------+4rowsinset (0.00sec)

同left join。


五、Cross join

cross join:交叉连接,得到的结果是两个表的乘积,即笛卡尔积


笛卡尔(Descartes)乘积又叫直积。假设集合A={a,b},集合B={0,1,2},则两个集合的笛卡尔积为{(a,0),(a,1),(a,2),(b,0),(b,1), (b,2)}。可以扩展到多个集合的情况。类似的例子有,如果A表示某学校学生的集合,B表示该学校所有课程的集合,则A与B的笛卡尔积表示所有可能的选课情况。

mysql>select*fromAcrossjoinB;
+----+-----------+----+-------------+|id|name|id|name|+----+-----------+----+-------------+|1|Pirate|1|Rutabaga||2|Monkey|1|Rutabaga||3|Ninja|1|Rutabaga||4|Spaghetti|1|Rutabaga||1|Pirate|2|Pirate||2|Monkey|2|Pirate||3|Ninja|2|Pirate||4|Spaghetti|2|Pirate||1|Pirate|3|DarthVader||2|Monkey|3|DarthVader||3|Ninja|3|DarthVader||4|Spaghetti|3|DarthVader||1|Pirate|4|Ninja||2|Monkey|4|Ninja||3|Ninja|4|Ninja||4|Spaghetti|4|Ninja|+----+-----------+----+-------------+16rowsinset (0.00sec)
#再执行:mysql> select * from A inner join B; 试一试#在执行mysql> select * from A cross join B on A.name = B.name; 试一试

实际上,在 MySQL 中(仅限于 MySQL) CROSS JOIN 与 INNER JOIN 的表现是一样的,在不指定 ON 条件得到的结果都是笛卡尔积,反之取得两个表各自匹配的结果。

INNER JOIN(或者用“,”表示)与 CROSS JOIN 可以省略 INNER 或 CROSS 关键字,因此下面的 SQL 效果是一样的:

... FROMtable1INNERJOINtable2... FROMtable1CROSSJOINtable2... FROMtable1JOINtable2

六、Full join

mysql>select*fromAleftjoinBonB.name=A.name->union->select*fromArightjoinBonB.name=A.name;
+------+-----------+------+-------------+|id|name|id|name|+------+-----------+------+-------------+|1|Pirate|2|Pirate||2|Monkey|NULL|NULL||3|Ninja|4|Ninja||4|Spaghetti|NULL|NULL||NULL|NULL|1|Rutabaga||NULL|NULL|3|DarthVader|+------+-----------+------+-------------+6rowsinset (0.00sec)

全连接产生的所有记录(双方匹配记录)在表A和表B。如果没有匹配,则对面将包含null。

MySQL本身不支持full join(全连接),但可以通过union来实现。

image.png


七、性能优化

1、显示(explicit) inner join VS 隐式(implicit) inner join

如:

select*fromtableainnerjointablebona.id=b.id;

VS

selecta.*, b.*fromtablea, tablebwherea.id=b.id;

我在数据库中比较(10w数据)得之,它们用时几乎相同,第一个是显示的inner join,后一个是隐式的inner join。

2.left join/right join VS inner join

尽量用inner join.避免 LEFT JOIN 和 NULL.

在使用left join(或right join)时,应该清楚的知道以下几点:

(1) on 与 where 的执行顺序


ON 条件(“A LEFT JOIN B ON 条件表达式”中的ON)用来决定如何从 B 表中检索数据行。如果 B 表中没有任何一行数据匹配 ON 的条件,将会额外生成一行所有列为 NULL 的数据,在匹配阶段 WHERE 子句的条件都不会被使用。仅在匹配阶段完成以后,WHERE 子句条件才会被使用。它将从匹配阶段产生的数据中检索过滤。


所以我们要注意:在使用Left (right) join的时候,一定要在先给出尽可能多的匹配满足条件,减少Where的执行。如:

PS:这部分有些不妥,感谢 wxweven 指正:


这部分的内容,博主写的有些欠妥当,不知道博主有没有实际运行测试过,下面说说我的看法:


(1)首先关于on和where的用法,如果直接把where里面的条件拿到on里面去,结果是跟原来的不一致的,所以博主说的“在使用Left (right) join的时候,一定要在先给出尽可能多的匹配满足条件,减少Where的执行”是不成立的,因为筛选条件放在on或者where,产生的是不同的结果,不能说为了性能就把where中的条件放到on中。


PASS

select*fromAinnerjoinBonB.name=A.nameleftjoinConC.name=B.nameleftjoinDonD.id=C.idwhereC.status>1andD.status=1;

Great

select*fromAinnerjoinBonB.name=A.nameleftjoinConC.name=B.nameandC.status>1leftjoinDonD.id=C.idandD.status=1

从上面例子可以看出,尽可能满足ON的条件,而少用Where的条件。从执行性能来看第二个显然更加省时。

(2) 注意 ON 子句和 WHERE 子句的不同

如作者举了一个列子:

mysql>SELECT*FROMproductLEFTJOINproduct_detailsON (product.id=product_details.id)
ANDproduct_details.id=2;
+----+--------+------+--------+-------+|id|amount|id|weight|exist|+----+--------+------+--------+-------+|1|100|NULL|NULL|NULL||2|200|2|22|0||3|300|NULL|NULL|NULL||4|400|NULL|NULL|NULL|+----+--------+------+--------+-------+4rowsinset (0.00sec)
mysql>SELECT*FROMproductLEFTJOINproduct_detailsON (product.id=product_details.id)
WHEREproduct_details.id=2;
+----+--------+----+--------+-------+|id|amount|id|weight|exist|+----+--------+----+--------+-------+|2|200|2|22|0|+----+--------+----+--------+-------+1rowinset (0.01sec)

从上可知,第一条查询使用 ON 条件决定了从 LEFT JOIN的 product_details表中检索符合的所有数据行。第二条查询做了简单的LEFT JOIN,然后使用 WHERE 子句从 LEFT JOIN的数据中过滤掉不符合条件的数据行。


(3) 尽量避免子查询,而用join

往往性能这玩意儿,更多时候体现在数据量比较大的时候,此时,我们应该避免复杂的子查询。如下:

PASS

insertintot1(a1) selectb1fromt2wherenotexists(select1fromt1wheret1.id=t2.r_id); 

Great

insertintot1(a1)  
selectb1fromt2leftjoin (selectdistinctt1.idfromt1 ) t1ont1.id=t2.r_idwheret1.idisnull;  

附:

image.png

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
6月前
|
存储 关系型数据库 MySQL
mysql中的left join、right join 、inner join的详细用法
【8月更文挑战第16天】在MySQL中,`INNER JOIN`、`LEFT JOIN`与`RIGHT JOIN`用于连接多表。`INNER JOIN`仅返回两表中匹配的行;`LEFT JOIN`保证左表所有行出现于结果中,右表无匹配时以NULL填充;`RIGHT JOIN`则相反,保证右表所有行出现于结果中。例如,查询学生及其成绩时,`INNER JOIN`仅显示有成绩的学生;`LEFT JOIN`显示所有学生及他们对应的成绩,无成绩者成绩列为空;`RIGHT JOIN`显示所有成绩及对应学生信息,无学生信息的成绩条目则为空。
210 1
|
6月前
|
SQL 关系型数据库 MySQL
Mysql中from多表跟join表的区别
Mysql中from多表跟join表的区别
410 0
|
7月前
|
SQL Java 数据库
MySQL设计规约问题之为什么应尽量避免使用子查询,而可以考虑将其优化为join操作
MySQL设计规约问题之为什么应尽量避免使用子查询,而可以考虑将其优化为join操作
|
10天前
|
关系型数据库 MySQL 数据库连接
数据库连接工具连接mysql提示:“Host ‘172.23.0.1‘ is not allowed to connect to this MySQL server“
docker-compose部署mysql8服务后,连接时提示不允许连接问题解决
|
15天前
|
缓存 关系型数据库 MySQL
【深入了解MySQL】优化查询性能与数据库设计的深度总结
本文详细介绍了MySQL查询优化和数据库设计技巧,涵盖基础优化、高级技巧及性能监控。
128 0
|
2月前
|
存储 Oracle 关系型数据库
数据库传奇:MySQL创世之父的两千金My、Maria
《数据库传奇:MySQL创世之父的两千金My、Maria》介绍了MySQL的发展历程及其分支MariaDB。MySQL由Michael Widenius等人于1994年创建,现归Oracle所有,广泛应用于阿里巴巴、腾讯等企业。2009年,Widenius因担心Oracle收购影响MySQL的开源性,创建了MariaDB,提供额外功能和改进。维基百科、Google等已逐步替换为MariaDB,以确保更好的性能和社区支持。掌握MariaDB作为备用方案,对未来发展至关重要。
66 3
|
2月前
|
安全 关系型数据库 MySQL
MySQL崩溃保险箱:探秘Redo/Undo日志确保数据库安全无忧!
《MySQL崩溃保险箱:探秘Redo/Undo日志确保数据库安全无忧!》介绍了MySQL中的三种关键日志:二进制日志(Binary Log)、重做日志(Redo Log)和撤销日志(Undo Log)。这些日志确保了数据库的ACID特性,即原子性、一致性、隔离性和持久性。Redo Log记录数据页的物理修改,保证事务持久性;Undo Log记录事务的逆操作,支持回滚和多版本并发控制(MVCC)。文章还详细对比了InnoDB和MyISAM存储引擎在事务支持、锁定机制、并发性等方面的差异,强调了InnoDB在高并发和事务处理中的优势。通过这些机制,MySQL能够在事务执行、崩溃和恢复过程中保持
96 3
|
2月前
|
SQL 关系型数据库 MySQL
数据库灾难应对:MySQL误删除数据的救赎之道,技巧get起来!之binlog
《数据库灾难应对:MySQL误删除数据的救赎之道,技巧get起来!之binlog》介绍了如何利用MySQL的二进制日志(Binlog)恢复误删除的数据。主要内容包括: 1. **启用二进制日志**:在`my.cnf`中配置`log-bin`并重启MySQL服务。 2. **查看二进制日志文件**:使用`SHOW VARIABLES LIKE 'log_%';`和`SHOW MASTER STATUS;`命令获取当前日志文件及位置。 3. **创建数据备份**:确保在恢复前已有备份,以防意外。 4. **导出二进制日志为SQL语句**:使用`mysqlbinlog`
99 2
|
2月前
|
关系型数据库 MySQL 数据库
Python处理数据库:MySQL与SQLite详解 | python小知识
本文详细介绍了如何使用Python操作MySQL和SQLite数据库,包括安装必要的库、连接数据库、执行增删改查等基本操作,适合初学者快速上手。
311 15
|
2月前
|
SQL 关系型数据库 MySQL
数据库数据恢复—Mysql数据库表记录丢失的数据恢复方案
Mysql数据库故障: Mysql数据库表记录丢失。 Mysql数据库故障表现: 1、Mysql数据库表中无任何数据或只有部分数据。 2、客户端无法查询到完整的信息。