一篇文章看懂MySQL的多表连接(包含左/右/全外连接)

news2024/9/20 6:12:49

MySQL的多表查询

这是第二次学习多表查询,关于左右连接还是不是很熟悉,因此重新看一下。小目标:一篇文章看懂多表查询!!

这篇博客是跟着宋红康老师学习的,点击此处查看视频,关于数据库我放在了Github中/Learn/MySQL/尚硅谷MySQL:资料下的aiguigu.sql文件中,可以直接点此处跳转到文件。

由于只有一个文件,因此在这里说一个Github的使用小技巧:在Github的页面中点击按钮可以打开网页端的VSCode,然后可以直接对整个文档进行Copy,然后在本地新建一个.sql文件粘贴进去就可以了。(Google Chrome浏览器是支持的,Firefox应该也可以,Safari测试了一下不支持,大家可以自行尝试。)

😈 1 v N | 一对多的情况

本办法实现多表查询:查找Abel所在的城市(查询结果就不写了,可以自己再Navicat或者命令行里面试一下)

SELECT  * FROM employees WHERE last_name='Abel'; # 先查找姓Abel的人 得到部门ID是80

SELECT * FROM departments WHERE department_id=80; # 查找部门id是80的部门信息,得到城市ID是2500

SELECT * FROM locations WHERE location_id=2500; # 查看城市ID是2500的城市信息

通过上述方式,我们可以在Service里面调用三次Mapper/SQL,得到结果,但是会大大增加网络IO,且查询结果不确定,甚至还要增加事务管理,完全犯不上,因此可以考虑使用多表查询。

或者将这些内容全部整合成一张表,比如员工表整合员工的城市ID(或者是城市信息)或者在部门ID整合城市信息,甚至可以将三张表整合为一张表,每个员工都包含部门、城市信息,但是考虑到在大型项目中,可能会有几百几千张表,那么将这些表全部整合的话,会增加每次查询的吞吐量(每次查询可能都得几Mb的数据)是非常不便的,将表分开可以让我们达到需要什么数据就查询什么表的状态(大部分情况下可能都是单表查询),因此在开发之前应该考虑到如何分表,以方便数据库的使用以及最合理的使用数据库缓存。

🎨 多表查询如何实现?

🦈 笛卡尔积问题 | 交叉连接问题

直接从表里面查询employee_iddepartment_id,查询结果有2889条记录

SELECT employee_id,department_name FROM employees,departments; ## 查询结果有2000多条记录,但是员工才只有107个,这明显是不对的。

上述问题涉及到了一个叫笛卡尔积的问题(交叉连接问题),也就是A表中的每一条数据都与B表中的每一条数据组合成为一个查询结果

上图就是一个非常明显的笛卡尔积(但是不能被称为问题),A表中的每一条数据都与B表中的每一条数据做了对应,得到了一个a*b长度的结果,这个结果集就是笛卡尔积。

在实际使用中,我们可能只想要A表中数字与B表中数字相同的结果做组合,得到的结果就是 11/22/33,因此笛卡尔积的情况

加上连接条件之后就变成如下:

SELECT employee_id,department_name FROM employees,departments WHERE employees.`department_id`=departments.`department_id`;

在查询的时候, 我们每次都要写表名,这样可能会比较麻烦,可以通过取别名(使用空格或者AS关键字)的方式进行替换。如下:

SELECT emp.employee_id,dep.department_name FROM employees emp,departments dep WHERE emp.`department_id`=dep.`department_id`;
SELECT emp.employee_id,dep.department_name FROM employees AS emp,departments AS dep WHERE emp.`department_id`=dep.`department_id`;

注意,一旦使用别名,那么我们就需要替换查询语句中的所有的表名,比如将所有的表名employees替换为emp,取别名的方式仅在本次查询生效,不会影响数据库本身。

另外,多表查询的时候应该在查询结果字段前加上表名,这是一种SQL优化方式,可以避免字段太多时MySQL去各个表中查找该字段;

果查询的字段出现在了多个表中,则必须要加上所属表。

如果有n个表实现多表查询,则至少有n-1个链接条件

🎨 多表查询 | 连接方式

等值连接 VS 非等值连接

自连接 VS 非自连接

内连接 VS 外连接

等值连接 VS 非等值连接

在员工表中,存在员工的工资,而在工资表中,存储的是工资的等级,每个等级有上下限,也就是说在某个区间内的工资可以认为是等级X;现在要我们查询员工的id、last_name以及工资等级,因此我们需要使用得等值连接(大于小于或者between)来连接两个表

SELECT e.last_name,e.salary,j.grade_level # 查询结果的关键字
FROM employees AS e,job_grades AS j # 查询的表(取别名)
WHERE e.`salary` BETWEEN j.lowest_sal AND j.highest_sal # 查询条件
ORDER BY e.salary DESC; # 排个序(降序),看着方便

自连接 VS 非自连接

自连接如下:

在员工表中,每一个员工都有一个管理者ID,该ID同时又是此表中其他员工的ID,因此可以通过自连接的方式进行查询:同一个表,去两个别名。

SELECT e.`manager_id` '员工ID',e.last_name AS '员工姓名',m.employee_id '管理者ID',m.last_name AS '管理者姓名'
FROM employees e,employees m
WHERE e.`manager_id` = m.`employee_id`;

以上查询中,我们分别给employees表取了两个别名,分别是e(employees/员工)m(manager/管理者),将这一张表看做是两张表,然后通过条件将它们关联起来。

注意:查询结果中我特意使用了别名,加不加AS关键字都可以,别名可以更加方便阅读。

内连接 VS 外连接 (有点难但是很重要)

内连接:(上面写的全都是内连接)连接条件只是将几个表的某些字段做了一个简单的对应的就是内连接,并没有用到这些表的所有字段。

外连接:与内连接字段的匹配不同,外连接是行的匹配。(比如用户表有id、name、age,那么id就是一个字段,name、age分别为两个字段,但是id、name、age这三个字段组成一个行,在数据库中作为一条记录显示,将此行与另一个表的行做链接,就被称为外连接)


在讲内外链接之前,我们要了解JOIN ... ON...的写法,JOIN...ON...的写法并不只是适用于外连接,同时也适用于内连接。我们可以通过[INNER] JOIN ... ON ... 的方式来实现一个内连接(INNER可省略);将需要关联的表放在JOIN后面,条件放在ON里面(不用写WHERE关键字)

与逗号分隔符+WHERE关键字的区别:WHERE关键字的话写法上更加简单,但是(个人觉得)可阅读性较差,而JOIN...ON...的方式写法上比较复杂,但是阅读星(也没有好到哪里去)。

JOIN...ON...还有一点区别于WHERE的是:WHERE只可以写一次,然后里面如果有多个条件可以使用分隔符分开,但是JOIN可以使用类似于链式编程的方式,也就是JOIN ... ON ... JOIN ... ON ... JOIN ... ON... ... 这样的写法,将每一个表的条件单独写在一个ON中。


外连接分为:满外连接、左外连接、右外连接

如果是左外连接,那么左表就是主表右表称为从表;右外连接与之相反。左外连接出了返回满足连接条件的行之外,还会返回左表中不满足条件的行;右外连接与之相反。

注意!!SQL92语法与SQL99语法实现外连接有所不同,SQL92比较简单一些,但是可读性较差,但是MySQL不支持SQL92语法。的方式。

正如本小节第二段所介绍,内外连接都可以使用JOIN...ON...,区别在于内连接前面(可选)可以写一个INNER关键字,而外连接则必须要写LEFT/RIGHT [OUTER]关键字,如下(下面的例子也有SQL92语法,建议在Oracle数据库中进行尝试)

🍁 左外右外连接

左右外连接可以查询到主表对应从表是空的内容,也就是说主表中的关键字全部都显示出来。

查询全部员工的last_name与department_name信息,其中last_name存储在员工表中,department_name存储在部门表中。

由于老板并没有所属的部门,因此总共员工107,如果不使用外连接的话只会查询到106条记录,因此要使用外连接。

SQL92语法实现外连接,使用+加号 (注意:MySQL不支持SQL92语法)

SELECT e.employee_id,d.department_name
FROM employees e,departments d
WHERE e.`department_id` = d.`department_id`(+);

SQL99语法中实现左外连接

SELECT last_name,department_name
FROM employees e LEFT OUTER JOIN departments d
ON e.`department_id`=d.`department_id`;

以上查询可以查找到107条数据,也就是没有部门的老板也能找到。如果将LEFT换成RIGHT的话,则会查到更多的结果,因为非常多的部门里面是没有用户的。

🍁 满外连接

满外连接的关键字是FULL,但是很遗憾,MySQL还是不支持(Oracle数据库支持,只要将LEFT/RIGHT关键字换为FULL就可以,在此不举例子了)。

如果要在MySQL中使用满外连接,需要使用UBION关键字查询结果合并,如下图所示:

👾 UNION 与 UNION ALL 关键字 | 合并查询结果 | MySQL中满外连接的实现

什么是UNION关键字,UNION关键字可以将两个查询结果合并起来,比如我们要得到一个满外连接, 就可以将下图左上角的图+右中的图相加,得到左下角的图。

UNION ALL关键字:UNION ALL关键字不会去除重复数据,左上与右上图相加,就是一个UNION ALL,因为中间的部分不会删除

在开发中,能用UBION ALL就用UNION ALL,坚决少用UNION(因为会多一个去重,增加时间)

满外连接也属于外连接的一种,由于MySQL不支持FULL关键字,因此变得比较复杂,所以单独做一个小节

上图中7中JOIN的实现

🥥 中间的图 : 内连接

# 106 条记录
SELECT employee_id,department_name
FROM employees e JOIN departments d
ON e.`department_id` = d.`department_id`;

🥥 左上图: 左外连接

# 107 条记录
SELECT employee_id,department_name
FROM employees e LEFT JOIN departments d
ON e.`department_id`= d.`department_id`;

🥥 右上图: 右外连接

# 122 条记录
SELECT employee_id,department_name
FROM employees e RIGHT JOIN departments d
ON e.`department_id`= d.`department_id`;

🥥 左中图

左中图在左上图的基础上过滤掉了中间的图

# 1 条记录
SELECT employee_id,department_name
FROM employees e LEFT JOIN departments d
ON e.`department_id`= d.`department_id`
WHERE d.department_id IS NULL;

🥥 右中图

与左中图同理,都是删除了中间部分

SELECT employee_id,department_name
FROM employees e RIGHT JOIN departments d
ON e.`department_id`= d.`department_id`
WHERE d.department_id IS NULL;

🥥 左下图: 全外连接

左上+右中 | UNION ALL
SELECT employee_id,department_name
FROM employees e LEFT JOIN departments d
ON e.`department_id`= d.`department_id`
UNION ALL
SELECT employee_id,department_name
FROM employees e RIGHT JOIN departments d
ON e.`department_id`= d.`department_id`
WHERE d.department_id IS NULL;
左中+右上 | UNION ALL
SELECT employee_id,department_name
FROM employees e LEFT JOIN departments d
ON e.`department_id`= d.`department_id`
WHERE d.department_id IS NULL
UNION ALL 
SELECT employee_id,department_name
FROM employees e RIGHT JOIN departments d
ON e.`department_id`= d.`department_id`;
左上+右上 | UNION (不推荐)
SELECT employee_id,department_name
FROM employees e LEFT JOIN departments d
ON e.`department_id`= d.`department_id`
UNION
SELECT employee_id,department_name
FROM employees e RIGHT JOIN departments d
ON e.`department_id`= d.`department_id`;

🥥 右下图 | 左中+右中

SELECT employee_id,department_name
FROM employees e LEFT JOIN departments d
ON e.`department_id`= d.`department_id`
WHERE d.department_id IS NULL
UNION ALL
SELECT employee_id,department_name
FROM employees e RIGHT JOIN departments d
ON e.`department_id`= d.`department_id`
WHERE d.department_id IS NULL;

自然连接 | SQL 99 语法新特性

NATURAL JOIN,会自动查询两张链接表中所有相同字段,然后进行等值连接

SELECT employee_id,last_name,department_name
FROM employees e NATURAL JOIN departments d;

方便,但是不够灵活

USING | SQL 99 语法新特性

SELECT employee_id,last_name,department_name
FROM employees e JOIN departments d
USING (department_id)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/459438.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

主动式电容笔是什么?苹果平替电容笔性价比高的推荐

苹果Pencil在市场上有需求吗?苹果的原装电容笔,虽然功能强大,但价格却非常的昂贵。当然,你也可以用这个苹果Pencil,不过,如果你不想花大价钱买它,就可以选一支平替的电容笔。就当前的科技水平而…

黑客利用WordPress 插件暗中建立后门网站

东方联盟网络安全组织在上周发布的一份报告中透露,有人观察到威胁行为者利用一个合法但过时的 WordPress 插件暗中建立后门网站,作为正在进行的活动的一部分。 有问题的插件是 Eval PHP,由名为 flashpixx 的开发人员发布。它允许用户插入 PH…

从需求分析到上线发布,一步步带你开发收废品小程序

在如今的环保和可持续性的大趋势下,废品回收已经成为了人们日常生活中不可或缺的一部分。收废品小程序的开发可以帮助人们更方便地找到回收废品的地点,并有效减少废品对环境造成的污染。因此,我们的收废品小程序需要满足以下需求:…

Google Play编写长描述的最佳实践

在我们为应用编写详细说明时,要遵循以下建议: 我们作为应用营销人员,要了解受众群体的需求和顾虑,如果不知道用户关心什么,那么我们可以查看关键词的搜索量、每个关键词的 Google Play 安装报告、当前关键字排名等等。…

数据湖Iceberg-Hive集成Iceberg(3)

文章目录 Hive集成Iceberg环境准备Hive与Iceberg的版本对应关系如下上传jar包,拷贝到Hive的auxlib目录中修改hive-site.xml,添加配置项启动 HMS 服务启动 Hadoop 创建和管理 Catalog默认使用 HiveCatalog指定 Catalog 类型使用 HiveCatalog使用 HadoopCa…

HTML+CSS+JS 学习笔记(三)———Javascript(下)

🌱博客主页:大寄一场. 🌱系列专栏:前端 🌱往期回顾:HTMLCSSJS 学习笔记(三)———Javascript(上) 😘博客制作不易欢迎各位👍点赞⭐收藏➕关注 目录 JavaScrip…

【ChatGPT】如何让 ChatGPT 不再频繁报错,获取更加稳定的体验?

文章目录 一、问题描述二、方案1:使用 OpenAI API Key 来访问 ChatGPT三、方案2:安装 Chrome 插件3.1 介绍3.2 安装步骤3.2.1 插件 & 脚本安装3.2.2 解读功能 一、问题描述 最近一段时间,相信大家都发现了 ChatGPT 一个问题,…

阿里二面:Spring用到了哪些设计模式?

代理模式 所谓代理,是指它与被代理对象实现了相同的接口,客户端必须通过代理才能与被代理的目标类进行交互,而代理一般在交互的过程中(交互前后),进行某些特定的处理,比如在调用这个方法前做前…

计算机网络|第二章:应用层

分层体系结构回顾 在本章中,我们学习有关网络应用的原理和实现方面的知识。 我们从定义关键的应用层概念开始,其中包括应用程序所需要的网络服务、客户和服务器、进程和运输层接口。详细考察几种网络应用程序,包括Web、电子邮件、DNS、对等文…

工业一体机在CNC机台起到什么作用?

随着工业自动化的不断发展,CNC机床已经成为现代制造业的重要设备之一。而工业一体机在CNC机台则是CNC机床的一种新型形态,其具有全封闭式设计、高精度、高效率等特点,广泛应用于各种制造行业。 全封闭工业一体机 一、工业一体机的功能&#x…

部门来了个软件测试工程师,听说是00后,上来一顿操作给我看呆了...

公司新来了个同事,听说大学是学的广告专业,因为喜欢IT行业就找了个培训班,后来在一家小公司实习半年,现在跳槽来我们公司。来了之后把现有项目的性能优化了一遍,服务器缩减一半,性能反而提升4倍!给公司省了…

ArcGIS中加载在线地图系列:风格12

前言: ArcGIS作为最强大的地理数据处理、编辑、制图和地图服务发布、管理等的GIS平台,在不同的专业都可以看到它的身影。对于那些利用GIS信息进行编辑,设计的专业人士来说,其桌面端ArcMap备受欢迎。尤其是在可视化制图方面需求颇…

C++入门(C++)

目录 命名空间 1、命名空间的定义 2、命名空间的使用 1、加名空间名称和作用域限定符 2、使用using namespace 命名空间引入 3、使用using将命名空间中某个成员引入 C的输入与输出 缺省参数 1、缺省参数的概念 2、缺省参数分类 1、全缺省参数 2、半缺省参数 函数重载 1、函数重…

【数据库】索引和事务

目录 1.索引 1.1关于索引 索引是什么? 为什么要有索引? 索引的作用? 索引的优点和缺点? 1.2索引类型及创建 索引的分类 创建索引 1.3索引的数据结构 1.4索引覆盖 2.事务 2.1关于事务 概念 事务的使用 2.2事务的特…

智慧旅游丨“服务+获客”新模式

全面放开的第一个五一小长假即将来临,旅游企业、城市、景点等又将进入流量及经济“升级密码”阶段。目前,传统旅行社在客户服务、运营模式中仍存在诸多痛点: 全面放开后“假期出游潮”日益高涨,佳信针对这些“痛点”问题&#xff…

问题排查记录-ffmpeg链接libavfilter和libavcodec:未定义的引用

目录 一、问题背景 二、问题现象 2.1 ffmpeg测试例程 2.2 编译脚本 2.3 错误提示 三、问题排查 3.1 关于提示找不到“stdio" "iostream"头文件的问题 3.1.1查看工具链头文件检索位置 3.1.2 根据工具链路径查找头文件 3.1.3 在编译脚本中指定头文件路径…

QT QPainter绘图之视口和窗口简介

1、视口和窗口的定义与原理 绘图设备的物理坐标是基本的坐标系,通过 QPainter 的平移、旋转等变换可以得到更容易操作的逻辑坐标。 为了实现更方便的坐标,QPainter 还提供了视口 (Viewport)和窗口 (Window)坐标系,通过QPainter 内部的坐标变…

【多线程】线程安全问题

1. 一段线程不安全的代码 我们先来看一段代码&#xff1a; public class ThreadDemo {public static int count 0;public static void main(String[] args) {for (int i 0; i < 10_0000; i) {count;}System.out.println("count " count);} } // 打印结果&…

Side Window Filtering 边窗滤波

原理分析 通常用常规图像算法做检测类的算法需要将图像特征增强&#xff0c;其中就需要滤波&#xff0c;把噪点去掉&#xff0c;如果直接用滤波&#xff0c;像高斯滤波&#xff0c;中值滤波&#xff0c;均值滤波等等&#xff0c;不仅会把噪点过滤掉&#xff0c;也会把图像的一些…

An error occurred during installation: No such plugin: cloudbees-folder

An error occurred during installation: No such plugin: cloudbees-folder Index of /packages/jenkins/plugins/cloudbees-folder 下载文件【cloudbees-folder.hpi】