【MySQL】复合查询+表的内外连接

2024-06-11 14:12

本文主要是介绍【MySQL】复合查询+表的内外连接,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

复合查询+表的内外连接

  • 1.基本查询回顾
  • 2.多表查询
  • 3.自连接
  • 4.子查询
    • 4.1单列子查询
    • 4.2多列子查询
  • 5.在from子句中使用子查询
  • 6.合并查询
  • 7.表的内连和外连
    • 7.1内连接
    • 7.2外连接
      • 7.2.1左外连接
    • 7.2.2右外连接

在这里插入图片描述

点赞👍👍收藏🌟🌟关注💖💖
你的支持是对我最大的鼓励,我们一起努力吧!😃😃

前面我们讲解的mysql表的查询都是对一张表进行查询,在实际开发中这远远不够,未来可能还有多表查询,子查询。

1.基本查询回顾

查询工资高于500或岗位为MANAGER的雇员,同时还要满足他们的姓名首字母为大写的J

下面有两种写法,都没问题

select * from emp where (sal>500 or job='MANAGER') and ename like 'J%';select * from emp where (sal>500 or job='MANAGER') and 'J'=substring(ename,1,1);

在这里插入图片描述

按照部门号升序而雇员的工资降序排序

select * from emp order by deptno asc,sal desc;

在这里插入图片描述

使用年薪进行降序排序

我们看到这个表奖金这一列有的是有的,有的是没有的为null,年薪=月薪*12+奖金
,但是null不参与运算,我们前面刚学的ifnull函数这个时候就可以用上了

在这里插入图片描述

ifnull(val1,val2),如果val1为null,返回val2,否则返回val1的值

select ename,sal*12+ifnull(comm,0) 年薪 from emp order by 年薪 desc;

在这里插入图片描述

显示工资最高的员工的名字和工作岗位
最高工资我们可以使用聚合函数做统计,但是聚合函数只是对一列的相同数据做聚合,今天还要有名字,所以单纯的做聚合是无法满足需求的,它只能最高工资是多少。名字和工作岗位显示不出来。

因此我们先找最高工资是多少。然后拿着这个最高工资去把这个人和工作岗位找到。很显然这是两句select。

在这里插入图片描述

但是这样写太挫了。怎么办呢,想办法把两个select查询语句合在一块写。
sql允许在一条sql内部在执行select查询,这称为子查询先执行内部的sql然后在执行外部的sql

select ename,job,sal from emp where sal=(select max(sal) from emp);

在这里插入图片描述

显示工资高于平均工资的员工信息

还是要先使用聚合函数把平均工资找到,然后在找到工资高于平均工资的员工。因此还可以使用子查询。

select * from emp where sal>(select avg(sal) from emp);

在这里插入图片描述

显示每个部门的平均工资和最高工资

首先是对部门分组,分组就是分表,表分好之后一个表内部门号是相同的,然后就是在每张表中找每个部门的平均工资和最高工资。其实在子表和在一个整表内找是一样的。在我看来不管是整表还是子表其实都是在表内查询。

select deptno,max(sal) 最高,avg(sal) 平均 from emp group by deptno;

在这里插入图片描述

显示平均工资低于2000的部门号和它的平均工资

这里要的是平均工资低于2000的部门号,因此要按照部门号分组,统计出每个部分的平均工资,然后在筛选出低于2000的部门号和平均工资

select deptno,avg(sal) myavg from emp group by deptno having myavg<2000;

在这里插入图片描述

显示每种岗位的雇员总数,平均工资

这个不就是对岗位分组,然后在统计每个岗位的人数和平均工资

select job,count(*),avg(sal) from emp group by job;

在这里插入图片描述

2.多表查询

以前我们都是从一张表拿数据,但是实际开发中往往数据来自不同的表,所以需要多表查询。

显示雇员名、雇员工资以及所在部门的名字

在这里插入图片描述
我们发现上面emp表中是没有部门名称的,换句话说要的数据是从两张表来的。
员工名和员工工资来自于emp表,部门名称来来自于dept表,因此注定了我们要将两个表做整合然后在查询。

select * from emp,dept;

可以看到形成了一张大表,仔细观察一下,将两张表信息做整合的时候,就光SMITH这一条消息就和整个dept表做组合形成了更多的记录,发现下面都是这样的。

在这里插入图片描述

我们可以看到如果今天对两张表的信息做组合,新形成表本质是将两张表中数据进行穷举组合的结果。我们把它称之为笛卡尔积。

在我们看来这不就是把两张表变成了一张表吗。所以未来在做数据的查找的时候,不就还是相当于单表的查找吗!然后就可以按照条件筛选出想要的信息。注意穷举是把所有组合结果都放在一起了,但是有些信息是有无意义的,因此可以先去除无意义的信息(不过还是看具体情况在决定是否保留),然后在按条件查找。

去除无效信息

在这里插入图片描述

在按条件筛选

在这里插入图片描述
在我们看来mysql一切皆表,换句话说这里做笛卡尔积之后,它形成的组合结果也是表结构,然后按照条件筛选
在这里插入图片描述

显示部门号为10的部门名,员工名和工资

select ename,sal,emp.deptno,dept.dname from emp,dept where emp.deptno=dept.deptno;

注意,如果指定的字段是这个表中是唯一的字段,不用指定表名直接显示即可,如果不是这个表中唯一的字段就需要指定表名显示,用来区分要显示是那个表的字段。

在这里插入图片描述

显示各个员工的姓名,工资,及工资级别
emp表中有员工的姓名和工资,工资级别在工资表里的,因此也还要将两个表笛卡尔积。

select ename,sal,grade from emp t1,salgrade t2 where t1.sal between t2.losal and t2.hisal;

在这里插入图片描述

上面我们是将两个不同的表做笛卡尔积,那可不可以把同一张表做笛卡尔积呢?

3.自连接

自连接是指同一张表做笛卡尔积。

我们发现直接把同一张表做笛卡尔积是不行的。主要原因这是同一张表这样不太好,字段名有重复不知道用的是那个表的字段名。

在这里插入图片描述

因此我们可以给两个表做重命名

重命名也可以对表进行重命名,一旦对表进行重命名之后几乎可以在这条sql语句任何地方出现。因为sql语句执行一定是先告诉是从那个表拿数据。

在这里插入图片描述

我们看到同一个表也是拿着前面的表每一条记录去和后面的表中所有记录做组合。所以哪怕是同一张表也可以做笛卡尔积,只不过是对表名重新命名一下即可。

显示员工FORD的上级领导的编号和姓名(mgr是员工领导的编号–empno)

在这里插入图片描述

我们首先会想到把这个人的领导编号拿到,然后根据这个编号在去找这个人拿到他的信息。两条select查询语句,但是我们可以把两个整和成一条sql语句

select empno,ename from emp where empno=(select mgr from emp where ename='FORD');

在这里插入图片描述

还有一种做法,我们发现 先找到FORD的领导编是要从 EMP 表中找,然后根据领导编号找领导信息也是要从 EMP 表中找。 因此我们可以把同一张表自连接然后再找。

在这里插入图片描述

select t2.empno,t2.ename from emp t1,emp t2 where t1.mgr=t2.empno and t1.ename='FORD';

在这里插入图片描述

4.子查询

在之前编写的时候,子查询我们也写了一些。现在我们正式来说一下子查询的概念。除了刚才的笛卡尔积是一种整合表的做法,子查询也是多表查询或者一张表中复杂查询时常用的做法。

子查询是指嵌入在其他sql语句中的select语句,也叫嵌套查询
一般我们在子查询时依赖的永远都是子查询查出来的结果,根据结果我们可以把子查询划分为单列单行子查询、单例多行子查询、多列单行子查询、多列多行子查询。

4.1单列子查询

单例单行子查询

显示SMITH同一部门的员工

首先会执行子查询将SMITH的部门号查出来,然后充当外面select的筛选条件。

select * from emp where deptno=(select deptno from emp where ename='SMITH');

子查询筛选出来的是单列单行的信息。

在这里插入图片描述

单列多行子查询

子查询筛选出来的是单例多行的信息。

in关键字 判断一个列值是否在集合中。
查询和10号部门的工作岗位相同的雇员的名字,岗位,工资,部门号,但是不包含10自己的

select ename,job,sal,deptno from emp where job in(select job from emp where deptno) and deptno<>10;

在这里插入图片描述

查询和10号部门的工作岗位相同的雇员的名字,岗位,工资,部门号,但是不包含10自己的,并且知道对应的员工属于哪一个部门的名字

还想要名字怎么办呢,但是emp里面并没有部门名字,只有dept表里面有。结合刚才所学,我们可以进行多表查询。首先确定一定要用的是dept表,还有一张表用谁呢?刚才我们不是已经得到一张表了。所以就把dept表和刚才的表做笛卡尔积。

子查询不仅可以在where充当筛选条件,还可以在from中,先用下面在解释。

在这里插入图片描述

然后去除不对的信息,就得到我们要的数据了

select ename,job,sal,tmp.deptno,dname from (select ename,job,sal,deptno from emp where job in(select job from emp where deptno=10) and deptno<>10) as tmp,dept where tmp.deptno=dept.deptno;

在这里插入图片描述

我们不仅仅用子查询把要的结果筛选出来,我想说的是,一个SQL整体的查询结果本身就是表结构,mysql一切解表,所以不要认为只有物理上真实存在的表才可以做笛卡尔积,我们可以将一个查出来的表结构也可以和其他表或者其他查询结果做笛卡尔积。其次,子查询不仅能出现在where后面充当判断条件,而且也能出现在from后面充当笛卡尔积。 在from哪里解释。

显示工资比部门30的所有员工的工资高的员工的姓名、工资和部门号
可能会想到先把30号部门最高工资先拿到,然后在去筛选比30号部门最高工资还高的信息。

在这里插入图片描述

下面这种写法我们也是先查找30部分最高工资然后充当筛选条件,在筛选

select ename,sal,deptno from emp where sal>(select max(sal) from emp where deptno=30);

在这里插入图片描述

除了这样的写法之外,我们还有一种做法,先把30号部门工资筛选出来,然后使用
all关键字 表示全部

select ename,sal,deptno from emp where sal>all(select distinct sal from emp where deptno=30);

在这里插入图片描述

显示工资比部门30的任意员工的工资高的员工的姓名、工资和部门号(包含自己部门的员工)
只要比30号部分任意一个人工资高就可以了
any关键字 表示任意

select ename,sal,deptno from emp where sal>any(select distinct sal from emp where deptno=30);

在这里插入图片描述

4.2多列子查询

单行子查询是指子查询只返回单列,单行数据;多行子查询是指返回单列多行数据,都是针对单列而言的,而多列子查询则是指查询返回多个列数据的子查询语句。

查询和SMITH的部门和岗位完全相同的所有雇员,不含SMITH本人

select * from emp where (deptno,job)=(select deptno,job from emp where ename='SMITH') and ename<>'SMITH';

子查询查出来的多列单行,没关系mysql支持( ,)

在这里插入图片描述

select * from emp where (deptno,job) in (select deptno,job from emp where ename='SMITH') and ename<>'SMITH';

我们发现这里也支持子查询多列多行

在这里插入图片描述

目前全部的子查询,全部都在where子句中,充当判断条件!但是任何时刻,查询出来的临时结构,本质在逻辑上也是表结构!

5.在from子句中使用子查询

子查询不仅可以出现where中充当判断条件,也可以出现在from中,from是在sql中告诉数据库去那个表里拿数据。在这里说一下任意查出来的表结构在我看来全都是表结构。子查询语句出现在from子句中,把一个子查询结果当做一个临时表使用,可以解决很多问题。

显示每个高于自己部门平均工资的员工的姓名、部门、工资、平均工资
首先我们要把每个部门的平均工资拎出来,如果找呢?那就需要分组然后聚合统计了。然后找出高于自己部门平均工资的姓名、部门、工资、平均工资。这个怎么找呢?如果你想的子查询找出自己部门的平均工资然后在做筛选找出这个部门中高于平均工资的,你会发现你做不下去的,因为今天这里并不是一个部门。首先我们先把每个部门平均工资拿出来走一步看一步。

select deptno,avg(sal) myavg from emp group by deptno;

按照之前这就是多列多行子查询,然后在子查询去where中筛选可能就比较麻烦了

在这里插入图片描述

可以看我们目前有什么,目前我们有部门号和部门平均工资,在我看来这就是一张表,然后我手里还有一张员工表,所以是不是可以把两张表做笛卡尔积,做完之后每个员工它所在那个部门已经所在部门的平均工资,在新的表中不就有了吗

子查询做表必须要给一个别名

select * from emp,(select deptno,avg(sal) myavg from emp group by deptno) tmp;

这个笛卡尔积将两张表的信息做了穷举,可是做完笛卡尔积有些信息是有意义的,有些一看就无意义的的,就如一个员工所属部门它目前并不需要和它不是同一个部门号的平均工资做对比,如果将来需要再说。因此可以过滤掉。

在这里插入图片描述

select * from emp,(select deptno,avg(sal) myavg from emp group by deptno) tmp where emp.deptno=tmp.deptno;

筛选之后,现在这不就是一张符合条件的单表查询了吗

在这里插入图片描述

然后在这张表里,在筛选出需要的信息就可以了

select ename,emp.deptno,sal,myavg from emp,(select deptno,avg(sal) myavg from emp group by deptno) tmp where emp.deptno=tmp.deptno and sal>myavg;

在这里插入图片描述

如果再加要求呢,要求这些人的办公地点在哪里?很简单我们可以把上面筛选出来的表结构充当一个表然后再和物理存在的dept表做笛卡尔积。

然后不又得到一张表了吗

在这里插入图片描述

然后只把有意义的消息筛选出来,

select * from dept,(select ename,emp.deptno,sal,myavg from emp,(select deptno,avg(sal) myavg from emp group by deptno) tmp where emp.deptno=tmp.deptno and sal>myavg) tmp where dept.deptno=tmp.deptno;

在这里插入图片描述

在把谁在哪里上班,部门号是多少消息拿出来不就好了吗

select tmp.ename,dept.loc,tmp.deptno from dept,(select ename,emp.deptno,sal,myavg from emp,(select deptno,avg(sal) myavg from emp group by deptno) tmp where emp.deptnmp.deptno=tmp.deptno and sal>myavg) tmp where dept.deptno=tmp.deptno;

在这里插入图片描述

只要你想做还可以在笛卡尔积。所以我们面对非常复杂的查询本质上都是在任务分解,复杂问题是由简单问题构成的。

查找每个部门工资最高的人的姓名、工资、部门、最高工资
首先也是要分组聚合统计找每个部门的最高工资,只不过只能统计到部门号和部门工资,这个人其他信息是没有办法在group by找到的。然后我们把这个临时表结构和emp做笛卡尔积。 最后在筛选出来部门号相同的,这个时候不有我们想要的信息的一张表了吗,然后在筛选自己想要的信息。

在这里插入图片描述

然后筛选出部门号相同的信息,最后找出自己要的数据就可以了

select ename,sal,emp.deptno,mymax from emp,(select deptno,max(sal) mymax from emp group by deptno) tmp where emp.deptno=tmp.deptno and sal=mymax;

在这里插入图片描述

记住mysql一切皆表,所谓的一切皆表就意味着可以把查询出来的临时结果在from后面也充当表。

显示每个部门的信息(部门名,编号,地址)和人员数量
首先人员数量一定是聚合出来的员工表里面是没有这个信息的。其次部门名、编号、地址是在dept表里面的。因此我们还可以像上面的做法一样解决。

select t1.deptno,dname,loc,mycnt from dept t1,(select deptno,count(*) mycnt from emp group by deptno) t2 where t1.deptno=t2.deptno;

在这里插入图片描述

其实还有一种方法就是单纯使用多表,不涉及子查询,不过这样太简单粗暴了,不够优雅!直接对emp表和dept表做笛卡尔积,然后筛选出部门和相同的一张表,然后对这张表做分组,分组之后在做聚合统计。

select t2.deptno,t2.dname,t2.loc,count(*) mycnt from emp t1,dept t2 where t1.deptno=t2.deptno group by t2.deptno,t2.dname,t2.loc;

要的信息除了部门号和人员数量,还有编号和地址,但是根据我们前面所学知识知道分组聚合统计只有跟在group by后面的列和聚合函数才可以聚合情况下出现,因此还要对编号和地址分组。

在这里插入图片描述

这种方法并不推荐,推荐使用子查询多表这种方法。

总结一下:mysql在我的心里是没有多表结构的,永远就是一张表。group by在我看来也是一张表,分组就是分表。只要解决一个问题其他都是解决。 多张表我可以在where中充当判断条件,在from中也做一个表然后和其他表做笛卡尔积。所以根本就没有多表问题。

解决多表问题的本质:想办法将多表转化成为单表,所以mysql中,所有select的问题全部都可以转成单表问题!这就是我们多表查询的指导思想!

6.合并查询

在实际应用中,为了合并多个select的执行结果,可以使用集合操作符 union,union all,合并并不是笛卡尔积,笛卡尔积是将两个表的信息穷举。合并就是单纯的合起来。

union
该操作符用于取得两个结果集的并集。当使用该操作符时,会自动去掉结果集中的重复行。

在这里插入图片描述

将工资大于2500或职位是MANAGER的人找出来
其实我们可以直接筛选出来的,但是我们用一下union

我们可以看到这两条sql查询出来的信息是有重复的。

在这里插入图片描述

这里我们可以使用union把两条sql合并起来并且去掉重复的

在这里插入图片描述

不想去重使用union all,就会把所有信息保留

在这里插入图片描述

注意合并时,两个表结构列必须是一样的才能把两个表合并起来

在这里插入图片描述

7.表的内连和外连

表的连接分为内连和外连

7.1内连接

内连接实际上就是利用where子句对两种表形成的笛卡儿积进行筛选,我们前面学习的查询都是内连接,也是在开发过程中使用的最多的连接查询。

除了上面学习的from 逗号 连接两个表然后用where筛选有效信息,还可以用下面inner join连接两个表,然后用on并且可以用and级联多个筛选条件 对笛卡尔积筛选出有效信息。之前学到的其实就是内连接的一种。

语法:

select 字段 from 表1 inner join 表2 on 连接条件 and 其他条件;

显示SMITH的名字和部门名称

这是之前的写法

select ename,emp.deptno,dname from emp,dept where emp.deptno=dept.deptno and ename='SMITH';

在这里插入图片描述

标准内连接写法

select ename,emp.deptno,dname from emp inner join dept on emp.deptno=dept.deptno where ename='SMITH';

两种写法都可以得到同样的数据,换句话说这种标准写法可以让我们的sql逻辑更清楚 ,哪一个部分是要形成笛卡尔积的,那一部分是进一步做条件筛选的。当然也直接用and连接,不过还是建议用where,逻辑更清楚。

在这里插入图片描述

7.2外连接

外连接分为左外连接和右外连接

7.2.1左外连接

如果多表查询,我们想让左侧的表完全显示不要过任何过滤筛选,如果和右侧的表配不上,让右侧的都为空也可以。必须保持左侧表的全貌。我们就叫做左外连接。

语法:

select 字段名 from 表名1 left join 表名2 on 连接条件

我们发现目前这两张表id是对不上的。

在这里插入图片描述

查询所有学生的成绩,如果这个学生没有成绩,也要将学生的个人信息显示出来

如果要用id做内连接的话,那只有1,2号学生符合条件,而我们要保留左侧表结构要完全显示,那内连接就不能满足条件了。因此我们使用左外连接

select * from stu left join exam on stu.id=exam.id;

左侧表完全保留,右侧表按条件拼接,条件满足直接拼上,条件不满足拼null

在这里插入图片描述

7.2.2右外连接

如果联合查询,要求右侧的表完全显示我们就说是右外连接。
其实只有左外连接也可以,把顺序换一下就可以,不过mysql这里也给我提供了右外连接。

语法:

select 字段 from 表名1 right join 表名2 on 连接条件;

对stu表和exam表联合查询,把所有的成绩都显示出来,即使这个成绩没有学生与它对应,也要显示出来

select * from stu right join exam on stu.id=exam.id;

右侧表完全保留,左侧表按条件拼接,条件满足直接拼上,条件不满足拼null

在这里插入图片描述

列出部门名称和这些部门的员工信息,同时列出没有员工的部门
首先是要将dept表和emp表做连接,要求的是必须把部门全部显示出来即使没有员工,这不是要求以dep表为主吗。

这里使用左外连接和右外连接都可以,不过就是换一下位置

select dept.dname,emp.* from dept left join emp on dept.deptno=emp.deptno order by dept.deptno asc;

在这里插入图片描述

select dept.dname,emp.* from emp right join dept on dept.deptno=emp.deptno order by dept.deptno asc;

在这里插入图片描述

这篇关于【MySQL】复合查询+表的内外连接的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1051398

相关文章

MySQL数据库双机热备的配置方法详解

《MySQL数据库双机热备的配置方法详解》在企业级应用中,数据库的高可用性和数据的安全性是至关重要的,MySQL作为最流行的开源关系型数据库管理系统之一,提供了多种方式来实现高可用性,其中双机热备(M... 目录1. 环境准备1.1 安装mysql1.2 配置MySQL1.2.1 主服务器配置1.2.2 从

深入理解Mysql OnlineDDL的算法

《深入理解MysqlOnlineDDL的算法》本文主要介绍了讲解MysqlOnlineDDL的算法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小... 目录一、Online DDL 是什么?二、Online DDL 的三种主要算法2.1COPY(复制法)

mysql8.0.43使用InnoDB Cluster配置主从复制

《mysql8.0.43使用InnoDBCluster配置主从复制》本文主要介绍了mysql8.0.43使用InnoDBCluster配置主从复制,文中通过示例代码介绍的非常详细,对大家的学习或者... 目录1、配置Hosts解析(所有服务器都要执行)2、安装mysql shell(所有服务器都要执行)3、

k8s中实现mysql主备过程详解

《k8s中实现mysql主备过程详解》文章讲解了在K8s中使用StatefulSet部署MySQL主备架构,包含NFS安装、storageClass配置、MySQL部署及同步检查步骤,确保主备数据一致... 目录一、k8s中实现mysql主备1.1 环境信息1.2 部署nfs-provisioner1.2.

MySQL中VARCHAR和TEXT的区别小结

《MySQL中VARCHAR和TEXT的区别小结》MySQL中VARCHAR和TEXT用于存储字符串,VARCHAR可变长度存储在行内,适合短文本;TEXT存储在溢出页,适合大文本,下面就来具体的了解... 目录一、VARCHAR 和 TEXT 基本介绍1. VARCHAR2. TEXT二、VARCHAR

MySQL中C接口的实现

《MySQL中C接口的实现》本节内容介绍使用C/C++访问数据库,包括对数据库的增删查改操作,主要是学习一些接口的调用,具有一定的参考价值,感兴趣的可以了解一下... 目录准备mysql库使用mysql库编译文件官方API文档对象的创建和关闭链接数据库下达sql指令select语句前言:本节内容介绍使用C/

mybatis直接执行完整sql及踩坑解决

《mybatis直接执行完整sql及踩坑解决》MyBatis可通过select标签执行动态SQL,DQL用ListLinkedHashMap接收结果,DML用int处理,注意防御SQL注入,优先使用#... 目录myBATiFBNZQs直接执行完整sql及踩坑select语句采用count、insert、u

MySQL之搜索引擎使用解读

《MySQL之搜索引擎使用解读》MySQL存储引擎是数据存储和管理的核心组件,不同引擎(如InnoDB、MyISAM)采用不同机制,InnoDB支持事务与行锁,适合高并发场景;MyISAM不支持事务,... 目录mysql的存储引擎是什么MySQL存储引擎的功能MySQL的存储引擎的分类查看存储引擎1.命令

MyBatis Plus大数据量查询慢原因分析及解决

《MyBatisPlus大数据量查询慢原因分析及解决》大数据量查询慢常因全表扫描、分页不当、索引缺失、内存占用高及ORM开销,优化措施包括分页查询、流式读取、SQL优化、批处理、多数据源、结果集二次... 目录大数据量查询慢的常见原因优化方案高级方案配置调优监控与诊断总结大数据量查询慢的常见原因MyBAT

一文详解MySQL索引(六张图彻底搞懂)

《一文详解MySQL索引(六张图彻底搞懂)》MySQL索引的建立对于MySQL的高效运行是很重要的,索引可以大大提高MySQL的检索速度,:本文主要介绍MySQL索引的相关资料,文中通过代码介绍的... 目录一、什么是索引?为什么需要索引?二、索引该用哪种数据结构?1. 哈希表2. 跳表3. 二叉排序树4.