MySQL --- 多表查询

多表查询、事物、以及提升查询效率最有手段的索引 

一. 多表查询

1.1 多表查询 --- 概述

1.1.1 数据准备

  • 将资料中准备好的多表查询数据准备的SQL脚本导入数据库中。

部门表:

员工表:

1.1.2 介绍

多表查询:指从多张表中查询数据,就是从多张表当中进行查询

单表查询的SQL语句:select 字段列表 from 表名;

那么要执行多表查询,只需要使用逗号分隔多张表即可,如: select 字段列表 from 表1, 表2;

查询用户表和部门表中的数据:

-- 多表查询:直接在from之后跟上多张表就可以了,多张表之间使用逗号分隔
select * from tb_depttb_emp,;

可以看到,在多表查询的结果当中,每个员工都展示了5次,将每个员工分别和五个部门进行了一次匹配, 也就是将17个员工和5个部门挨个组合了一次,就是17 * 5 = 85。

此时,我们看到查询结果中包含了大量的结果集,总共85条记录,而这其实就是员工表所有的记录(17行)与部门表所有记录(5行)的所有组合情况,这种现象称之为笛卡尔积。

笛卡尔积:笛卡尔乘积是指在数学中,两个集合(A集合和B集合它们)的所有组合情况。就相当于                      是把A集合当中的每一条记录都拿出来和B集合进行一个匹配。

                  总数据量 = A集合的数据量 * B集合的数据量

2 * 4 = 8条记录, 产生的这个结果被一个法国的数据加笛卡尔发现了,所以叫笛卡尔积。这个笛卡尔积是数学当中的一个概念,指的就是两个集合,A集合与B集合所有的组合情况。

我们知道一个员工只能归属于一个部门, 而其它无效数据我们是不需要的,所以多表查询的目的就是根据业务需求从多张表当中来查询数据,并且根据业务需要,要消除掉这些无效的笛卡尔积。

就拿当前这个例子来说,假如我们要查询的是每一个员工的信息以及员工对应的部门信息,那我们就可以将员工表当中部门ID这个字段与部门表的主键ID对应起来即可。而其它的这些数据,对于我们当前需求来说都是无效的笛卡尔积。

注意:在多表查询时,需要消除无效的笛卡尔积,只保留表关联部分的数据  

在SQL语句中,如何去除无效的笛卡尔积呢?

  • 只需要给多表查询加上连接查询的条件即可,通过连接查询的条件来消除无效的笛卡尔积。
-- 多表查询:直接在from之后跟上多张表就可以了,多张表之间使用逗号分隔
-- 在多表查询时,需要消除无效的笛卡尔积,只保留表关联部分的数据
-- 在SQL语句中,只需要给多表查询加上连接查询的条件即可去除无效的笛卡尔积
select * from tb_emp,tb_dept where tb_emp.dept_id = tb_dept.id;

在多表查询当中,消除无效的笛卡尔积之后,剩下的这一部分数据就是我们想要的正确的数据: 

由于id为17的员工,没有dept_id字段值,所以在多表查询时,根据连接查询的条件并没有查询到。

1.1.3 分类

在多表查询当中,根据查询的形式,我们将其分为两大类:一类是连接查询,一类是子查询 

多表查询可以分为:

1. 连接查询

    1. 内连接:相当于查询A表和B表,这两张表交集部分的数据

      2. 外连接

  • 左外连接:是以左表为基准,查询左表当中所有的数据(包括两张表交集部分的数据)

  • 右外连接:是以右表为基准,查询右表所有数据(包括两张表交集部分的数据)

2. 子查询:指的是在查询当中又嵌套了查询

1.2 内连接 

内连接查询:查询两表或多表中交集部分数据。 

 内连接从语法上可以分为:

  • 隐式内连接

  • 显式内连接

隐式内连接语法:

select  字段列表   from   表1 , 表2   where  条件 ... ;

显式内连接语法:

select  字段列表   from   表1  [ inner ]  join 表2  on  连接条件 ... ;
-- =============================内连接==============================
-- A.查询员工的姓名,及所属的部门名称(隐式内连接实现)
-- 隐式内连接:select 字段列表  from  表1,表2  where  条件...;
-- 提问:刚才所插入进来的员工表的测试数据一共有17条,为什么查询出来的结果只有16条呢?
-- 因为第17条员工的数据它是没有分配部门的,既然没有分配部门,说明这条记录它和部门表是没有关系的
-- 内连接查询的是两张表交集部分的数据,即A表当中没有和B表产生关联的数据是查询不出来的
select tb_emp.name,tb_dept.name from tb_emp,tb_dept where tb_emp.dept_id = tb_dept.id;
select tb_emp.name, tb_dept.name  -- 分别查询返回两张表中的数据
from tb_emp,tb_dept  -- 关联两张表
where tb_emp.dept_id = tb_dept.id; -- 连接查询条件消除笛卡尔积

-- 在多表查询时,如果表名较长写起来比较繁琐,可以给表起别名
select e.name as 员工姓名 , d.name as 部门名称 from tb_emp as e ,tb_dept as d where e.dept_id = d.id;

-- B.查询员工的姓名,及所属的部门名称(显示内连接实现)
-- 显式内连接:select  字段列表  from  表1  [inner]  join  表2  on  连接条件...;
select tb_emp.name,tb_dept.name from tb_emp inner join tb_dept on tb_emp.dept_id = tb_dept.id;

多表查询时给表起别名:

  • tableA as 别名1 , tableB as 别名2 ;

  • tableA 别名1 , tableB 别名2 ;

使用了别名的多表查询:

select emp.name , dept.name
from tb_emp emp inner join tb_dept dept
on emp.dept_id = dept.id;

注意事项:

一旦为表起了别名,就不能再使用表名来指定对应的字段了,此时只能够使用别名来指定字段。

1.3 外连接

外连接分为两种:左外连接 和 右外连接。

  • 左外连接:是以左表为基准,查询左表当中所有的数据(包括两张表交集部分的数据)

  • 右外连接:是以右表为基准,查询右表所有数据(包括两张表交集部分的数据)

左外连接语法结构:

select  字段列表   from   表1  left  [ outer ]  join 表2  on  连接条件 ... ;
  • 左外连接相当于查询表1(左表)的所有数据,当然也包含表1和表2交集部分的数据。

右外连接语法结构:

select  字段列表   from   表1  right  [ outer ]  join 表2  on  连接条件 ... ;
  •  右外连接相当于查询表2(右表)的所有数据,当然也包含表1和表2交集部分的数据。 

  • 我们把left outer join左侧的这张表也就是表1叫做左表,右侧的表2叫做右表。
  • 左外连接会完全包含左表,也就是表1当中的数据。中间outer关键字可以省略。
  • 如果是右外连接,会完全包含右表,也就是表2当中的数据。

 

-- =======================外连接================================
-- A.查询员工表中 所有 员工的姓名,和对应的部门名称(左外连接)
-- 注意看,要查询返回所有员工的姓名
-- 左外连接:select 字段列表 from 表1 left [outer] join 表2 on 连接条件...;
-- 由于是左外连接,因此会完全包含左表的数据,也就是tb_emp员工表的数据
select emp.name, dept.name
from tb_emp as emp
         left join tb_dept as dept on emp.dept_id = dept.id;

-- B.查询部门表中  所有  部门的名称,和对应的员工名称(右外连接)
-- 注意看,要查询返回所有部门的名称
-- 右外连接会完全包含右表的数据,即使右表当中有一部分数据和左表没有关联,也会查询出来
select emp.name as 员工姓名, dept.name as 部门名称
from tb_emp as emp
         right join tb_dept as dept on emp.dept_id = dept.id;

注意事项:

在我们项目开发当中,基本上使用的都是左外连接,右外连接使用的比较少,因为右外连接可以替换成左外连接。

左外连接和右外连接是可以相互替换的,只需要调整连接查询时SQL语句中表的先后顺序就可以了。而我们在日常开发使用时,更偏向于左外连接。

1.4 子查询

1.4.1 介绍

子查询:指的是在查询当中又嵌套了查询。

所谓子查询指的就是在SQL语句当中嵌套select查询语句,我们把嵌套的这个select查询语句叫做嵌套查询,也称为子查询。

这条查询语句的查询条件是取决于另外一个查询语句的。

SELECT  *  FROM   t1   WHERE  column1 =  ( SELECT  column1  FROM  t2 ... );
  • 子查询外部的语句可以是insert / update / delete / select 的任何一个,最常见的是 select。

根据子查询返回的结果不同,我们将子查询分为四类,根据子查询结果的不同分为:

  1. 标量子查询:子查询返回的结果为单个值[一行一列]

  2. 列子查询:子查询返回的结果为一列,但可以是多行

  3. 行子查询:子查询返回的结果为一行,但可以是多列

  4. 表子查询:子查询返回的结果为多行多列[相当于子查询结果是一张表]

表子查询指的是子查询返回的结果为多行多列,就相当于子查询返回的结果又是一张表。

子查询可以书写的位置:

  1. where之后

  2. from之后

  3. select之后

1.4.2 标量子查询 

  • 子查询返回的结果是单个值(数字、字符串、日期等),最简单的形式,这种子查询称为标量子查询。
  • 常用的操作符: = <> > >= < <=

-- ======================子查询===============================
-- 标量子查询:子查询返回的结果是一个单行单列的值
-- A.查询 "教研部" 的所有员工信息
-- 首先明确"教研部"是部门ID
-- a.查询 教研部 的部门ID --- tb_dept
select id from tb_dept where name = '教研部';  #查询结果:2
-- b.再查询该部门ID下的员工信息 --- tb_emp
select * from tb_emp where dept_id = 2;

-- 合并以上两条SQL语句,改写成一行
select * from tb_emp where dept_id = (select id from tb_dept where name = '教研部');


-- B.查询在 "方东白" 入职之后的员工信息
-- a.查询"方东白"的入职时间
select entrydate from tb_emp where name = '方东白';
-- b.再查询大于该入职时间的员工信息
select * from tb_emp where entrydate > '2012-11-01';

-- 合并以上两条SQL语句,改写成一行
select * from tb_emp where entrydate > (select entrydate from tb_emp where name = '方东白');

1.4.3 列子查询

  • 子查询返回的结果是一列(可以是多行),这种子查询称为列子查询。
  • 常用的操作符:in  、not in等

常用的操作符:

操作符描述
IN在指定的集合范围之内,多选一
NOT IN不在指定的集合范围之内
-- 列子查询:子查询返回的结果是一列多行
-- A.查询 "教研部" 和 "咨询部" 的所有员工信息
-- a.查询 "教研部" 和 "咨询部" 的部门ID --- tb_dept
-- 方式一:使用or关键字连接多个条件
select id from tb_dept where name = '教研部' or name = '咨询部'; #查询结果:3,2
-- 方式二:in关键字
select id from tb_dept where name in('教研部','咨询部');  #查询结果:3,2

-- b.根据部门ID,查询该部门下的员工信息 --- tb_emp
-- 方式一:使用or关键字连接多个条件
select * from tb_emp where dept_id = 3 or dept_id = 2;
-- 方式二:in关键字
select * from tb_emp where dept_id in (3,2);

-- 合并以上两条SQL语句,改写成一行
select * from tb_emp where dept_id in (select id from tb_dept where name in ('教研部','咨询部'));

 

1.4.4 行子查询

  • 子查询返回的结果是一行(可以是多列),这种子查询称为行子查询。
  • 常用的操作符:= 、<> 、IN 、NOT IN
-- 行子查询:查询返回的结果是一行多列
-- A.查询与 "韦一笑" 的入职日期及职位都相同的员工信息;
-- a.查询 "韦一笑" 的 入职日期 及 职位
select entrydate,job from tb_emp where name = '韦一笑'; #查询结果: 2007-01-01 , 2

-- b.查询与其入职日期 及 职位 都相同的员工信息
select * from tb_emp where entrydate = '2007-01-01' and job = 2;

-- 合并以上两条SQL语句,改写成一行
select *
from tb_emp
where entrydate = (select entrydate from tb_emp where name = '韦一笑')
  and job = (select job from tb_emp where name = '韦一笑');
-- 该SQL语句出现了多次子查询,性能其实并不高
-- 提问:怎么对这条SQL语句进行优化
-- 启发
select * from tb_emp where entrydate = '2007-01-01' and job = 2;
-- 改造
select * from tb_emp where (entrydate,job) = ('2007-01-01',2);

-- 正式改造,改造后只有一条子查询
select * from tb_emp where (entrydate,job) = (select entrydate,job from tb_emp where name = '韦一笑');

 

 1.4.5 表子查询

  • 表子查询指的是子查询返回的结果为多行多列,就相当于子查询返回的结果又是一张表。
  • 子查询返回的结果是多行多列,常作为临时表来使用,这种子查询称为表子查询。  
  • 既然是作为一张临时表,就经常会出现在select语句的from之后
  • 常用的操作符:in
-- 表子查询:子查询返回的结果是多行多列,常作为临时表来使用
-- A.查询入职日期是 "2006-01-01" 之后的员工信息,及其部门名称
-- a.查询入职日期是 "2006-01-01" 之后的员工信息
select * from tb_emp where entrydate > '2006-01-01'; #查询到一共有14条记录

-- 基于查询到的员工信息,在查询对应的部门信息
-- 把上面这条SQL语句查询返回的结果作为一张临时表来使用
-- b.查询这部分员工信息及其部门名称
-- [表名.*] 就代表这张表的所有信息
-- 这是隐式内连接查询,注意:陈友谅入职时间是2015-03-21,但是并没有查询到陈友谅的信息
-- 因为内连接查询的是两张表交集部分的数据
select emp.*, dept.name
from (select * from tb_emp where entrydate > '2006-01-01') as emp,
     tb_dept as dept
where emp.dept_id = dept.id; #查询到一共有13条记录,少了陈友谅


-- 改进上述SQL语句,使其能够查询到陈友谅的信息
-- 使用左外连接,使其员工表为左表
-- 因为左外连接是以左表为基准,查询左表当中所有的数据
select emp.*, dept.name
from (select * from tb_emp where entrydate > '2006-01-01') as emp
         left join tb_dept as dept on emp.dept_id = dept.id;

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

尚硅谷大数据技术Spark教程-笔记01【Spark(概述、快速上手、运行环境、运行架构)】

视频地址&#xff1a;尚硅谷大数据Spark教程从入门到精通_哔哩哔哩_bilibili 尚硅谷大数据技术Spark教程-笔记01【Spark(概述、快速上手、运行环境、运行架构)】尚硅谷大数据技术Spark教程-笔记02【SparkCore(核心编程、案例实操)】尚硅谷大数据技术Spark教程-笔记03【SparkSQL…

云原生背景下如何配置 JVM 内存

image.png 背景 前段时间业务研发反馈说是他的应用内存使用率很高&#xff0c;导致频繁的重启&#xff0c;让我排查下是怎么回事&#xff1b; 在这之前我也没怎么在意过这个问题&#xff0c;正好这次排查分析的过程做一个记录。 首先我查看了监控面板里的 Pod 监控&#xff1a;…

奶爸式Swagger教学

目录 一、导入依赖 二、SwaggerConfig基础编程 三、Swagger 常用说明注解 1.API 2.ApiOperation 3.ApiModel 4.ApiModelProperty 5.ApiParam 6.ApilmplicitParam 一、导入依赖 <!--开启Swagger --><!-- https://mvnrepository.com/artifact/io.springf…

Vector - 常用CAN工具 - CANoe软件安装常见问题

目录 一、确认电脑系统盘是否满足要求&#xff0c;CANoe软件对PC要求如下&#xff1a; 二、确认软件安装包完整 三、确认软件与电脑系统之间的兼容性 四、关闭后台程序 五、安装软件 六、清空临时文件夹 七、尝试在其他电脑上安装 一、确认电脑系统盘是否满足要求&#…

STM32 调试TM7711驱动原理图驱动代码

本文使用工程代码如下 (1条消息) STM32调试TM7711驱动原理图驱动源代码&#xff0c;参考如下博客&#xff0c;有原理图设计资源-CSDN文库 背景 项目选用TM7711&#xff0c;还是很令人吃惊的&#xff0c;主要是有如下几个理由 第一就是便宜 第二精度高 STM32的ADC精度不够…

微生物常见统计检验方法比较及选择

谷禾健康 微生物组经由二代测序分析得到庞大数据结果&#xff0c;其中包括OTU/ASV表&#xff0c;物种丰度表&#xff0c;alpha多样性、beta多样性指数&#xff0c;代谢功能预测丰度表等&#xff0c;这些数据构成了微生物组的变量&#xff0c;大量数据构成了高纬度数据信息。 针…

我的『1024』创作纪念日

目录 ◐机缘 ◑收获 ◐日常 ◑成就 ◐憧憬 记得&#xff0c;2020年07月22日我撰写了第1篇技术博客&#xff1a;《遗传算法实例解析》在这平凡的一天&#xff0c;我赋予了它不平凡的意义也许是立志成为一名专业T作者、也许是记录一段刚实践的经验但在那一刻&#xff0c;我已…

傅里叶分析的历史背景

目录 1. Fourier级数(三角级数)的历史背景 2. 圆和复平面 3. Fourier的大胆猜想 1. Fourier级数(三角级数)的历史背景 自古以来&#xff0c;圆形一直是(现在仍然是&#xff09;最简单的抽象理解形状。您只需要一个中心点和一个半径就可以了。圆上的所有点与圆心的距离都是固定…

Java Web开发:Spring Boot和Spring Cloud的应用和实践

一、介绍 Java Web开发是当今互联网时代中的一项重要技术&#xff0c;随着互联网的发展和应用场景的不断扩大&#xff0c;Java Web开发技术也得到了广泛的应用。而Spring Boot和Spring Cloud作为Java Web开发中最常用的技术之一&#xff0c;已经成为了很多开发者必备的技能。本…

Python常用的开发工具合集

​ Python是一种功能强大且易于学习的编程语言&#xff0c;被广泛应用于数据科学、机器学习、Web开发等领域。随着Python在各个领域的应用越来越广泛&#xff0c;越来越多的Python开发工具也涌现出来。但是&#xff0c;对于新手来说&#xff0c;选择一款合适的Python开发工具可…

Git的安装与版本控制

这里写目录标题 原理安装基本使用gitee-IDEA协同开发成员邀请开发组成员指定仓库权限给当前仓库设定分支提交代码时必须向自己的分支提交合并分支 - 无冲突 原理 Git本地有四个工作区域&#xff1a; 工作目录&#xff08;Working Directory&#xff09;、暂存区(Stage/Index)、…

【LeetCode】209.长度最小的子数组

209. 长度最小的子数组 思路一&#xff1a;暴力解法 通过两个for循环&#xff0c;从头开始找符合条件的子序列。暴力解法无法通过本题&#xff0c;超出时间限制&#xff0c;所以仅供参考。 代码如下&#xff1a; 暴力解法1&#xff1a;下面的代码是通过申请一个新的数组&#x…

error: LNK2001: 无法解析的外部符号 “public: virtual struct QMetaObject const * __cdecl

Qt系列文章目录 文章目录 Qt系列文章目录前言一、QtCreator中qmake命令是什么&#xff1f;2.解决 前言 我在代码中加入了对应的信号和槽&#xff0c;但编译仍然报错&#xff1a; #ifndef PROJECTWIN_H #define PROJECTWIN_Hnamespace Ui { class ProjectWin; }ProjectWin类声…

杂记——24.HTML中空格的写法

前几天写项目时&#xff0c;突然对HTML中空格的写法感兴趣&#xff0c;于是搜了一下&#xff0c;现在对其进行总结 HTML不是一种编程语言&#xff0c;而是一种超文本标记语言 (markup language)&#xff0c;是网页制作所必备的。超文本”就是指页面内可以包含图片、链接&#…

创建基于oracle jdk8的自定义docker镜像

创建基于oracle jdk8的自定义docker镜像 1:查看服务器java版本&#xff1a; 如果服务器的版本是open-jdk&#xff0c;则进行如下操作 拷贝相关jdk压缩包&#xff08;.tar.gz后缀&#xff09;到服务器目录&#xff08;例&#xff1a;/usr/local&#xff09; 解压&#xff1a;…

【18】SCI易中期刊推荐——计算机科学(中科院2区)

💖💖>>>加勒比海带,QQ2479200884<<<💖💖 🍀🍀>>>【YOLO魔法搭配&论文投稿咨询】<<<🍀🍀 ✨✨>>>学习交流 | 温澜潮生 | 合作共赢 | 共同进步<<<✨✨ 📚📚>>>人工智能 | 计算机视觉…

你真的会跟 ChatGPT 聊天吗?(下)

接《你真的会跟 ChatGPT 聊天吗&#xff1f;&#xff08;上&#xff09;》&#xff0c;本文下半部分没有无毛猫那么搞笑的内容啦&#xff01;即使如此&#xff0c;哪怕你对文中提及的技术不大了解&#xff0c;也可以毫无压力地看完这篇&#xff0c;描述如何更好地获得 ChatGPT …

Redis数据结构——动态字符串、Dict、ZipList

一、Redis数据结构-动态字符串 我们都知道Redis中保存的Key是字符串&#xff0c;value往往是字符串或者字符串的集合。可见字符串是Redis中最常用的一种数据结构。 不过Redis没有直接使用C语言中的字符串&#xff0c;因为C语言字符串存在很多问题&#xff1a; 获取字符串长度…

基于Python的学生成绩管理系统

末尾获取源码 开发语言&#xff1a;python 后端框架&#xff1a;django 数据库&#xff1a;MySQL5.7 开发软件&#xff1a;Pycharm 是否Maven项目&#xff1a;是 目录 一、项目简介 二、系统功能 三、系统项目截图 四、核心代码 4.1登录相关 4.2文件上传 4.3封装 一、项…

《程序员面试金典(第6版)》面试题 16.19. 水域大小(深度优先搜索,类似棋盘类问题,八皇后的简化版本,C++)

题目描述 你有一个用于表示一片土地的整数矩阵land&#xff0c;该矩阵中每个点的值代表对应地点的海拔高度。若值为0则表示水域。由垂直、水平或对角连接的水域为池塘。池塘的大小是指相连接的水域的个数。编写一个方法来计算矩阵中所有池塘的大小&#xff0c;返回值需要从小到…