前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MySQL复合查询

MySQL复合查询

作者头像
每天都要进步呀
发布2023-10-16 11:17:29
1820
发布2023-10-16 11:17:29
举报
文章被收录于专栏:C++/LinuxC++/Linux

前面我们讲解的mysql表的查询都是对一张表进行查询,在实际开发中这远远不够。

对于CURD之一的查找,他作为最重要的操作,仅仅在一张表之中查是不够的,还需要在多表之间进行查询,复合查询就是解决多表查询的问题。

一.基本查询回顾

image-20230730154249716
image-20230730154249716
  • 查询工资高于500或岗位为MANAGER的雇员,同时还要满足他们的姓名首字母为大写的J
image-20230730154510795
image-20230730154510795
  • 按照部门号升序而雇员的工资降序排序
image-20230730154914714
image-20230730154914714
  • 使用年薪进行降序排序

年薪=工资*12+奖金。而一些部门奖金为空,加起来后的结果自然也为空,故需要ifnull判断是否为空,若为空,则替换成0

image-20230730155211948
image-20230730155211948
  • 显示工资最高的员工的名字和工作岗位

此时,可以先找到最高的工资,然后通过这个工资找到对应的ename。但这种方式较为鸡肋,需要查两次,因此选择select嵌套的方式进行查找。先找等号右侧括号里的,然后再返回给外面。

image-20230730155658188
image-20230730155658188
  • 显示工资高于平均工资的员工信息

同样先将此信息分成两部分:一是找到高于平均工资的sal,二是通过此sal的匹配,找到对应的ename。

image-20230730155944736
image-20230730155944736
  • 显示每个部门的平均工资和最高工资

此时显示的是每个部门,而不是全公司,所以一定是要按照部门进行分组的。按照谁分组,查询时就可以将谁显示,因为这样相同的值可以压缩。

image-20230730160943966
image-20230730160943966

平均工资小数过多,用format函数将小数控制在两位:

image-20230730161009995
image-20230730161009995
  • 显示平均工资低于2000的部门号和它的平均工资

我们先将其分解:分组部门先找到平均工资低于2000的avg(sal),通过这个avg(sal)找到对应的部门号,存在分组的条件用having。

image-20230730160813702
image-20230730160813702
  • 显示每种岗位的雇员总数,平均工资
image-20230730161141405
image-20230730161141405

二.多表查询

实际开发中往往数据来自不同的表,所以需要多表查询。本节我们用一个简单的公司管理系统,有三张表EMP,DEPT,SALGRADE来演示如何进行多表查询。

image-20230730162147218
image-20230730162147218

将三个表以笛卡尔积的形式合并会得到一个包含三个表的全部信息的表。

image-20230730163710405
image-20230730163710405

但是为了去掉不对的组合,就需要where控制emp.deptno=dept.deptno

image-20230730164105611
image-20230730164105611
  • 显示部门号为10的部门名,员工名和工资
image-20230730164357557
image-20230730164357557
  • 显示各个员工的姓名,工资,及工资级别
image-20230730164543082
image-20230730164543082

三.自连接

1. 自连接的笛卡尔积

不同的表可以做笛卡尔积,那么同一张表也可以做笛卡尔积。自连接就是指在同一张表连接查询。

直接连接是不对的:

image-20230730170205842
image-20230730170205842

但是我们可以将其分别重命名,进行区分:

image-20230730170255196
image-20230730170255196

可以发现,重命名可以在from后出现,换句话说,重命名可以在任何地方出现。这样就完成了salgrade自己与自己的笛卡尔积。

2. 自连接案例

什么时候需要自连接呢?

当需要在同一张表通过一个字段找另一个字段,再通过另一个字段找到它对应的信息时,就需要进行自连接。

即拿emp表举例,显示员工FORD的上级领导的编号和姓名(mgr是员工领导的编号–empno)

image-20230730174700550
image-20230730174700550

那么此时就需要两步,先根据员工名FORD找到对应的mgr,再通过mgr与empno的对应,找到empno对应的编号和姓名。

此时,就需要将emp进行自连接,并进行查询:

代码语言:javascript
复制
select e2.empno, e2.ename from emp e1, emp e2 where e1.ename='FORD' and e1.mgr=e2.empno;
image-20230730175821197
image-20230730175821197

当然,通过子查询的方式也可以进行查找

先通过名字查询对应的mgr,再让empno=满足条件的mgr。

代码语言:javascript
复制
select empno, ename from emp where empno=(select mgr from emp where ename='FORD');
image-20230730180135782
image-20230730180135782

四.子查询

子查询是指嵌入在其他sql语句中的select语句,也叫嵌套查询。

1. 单行子查询

返回一行记录的子查询

就像刚刚所演示的子查询式的查找,在这里我们同样的展示一下:

  • 显示SMITH同一部门的员工
代码语言:javascript
复制
select * from emp where deptno = (select deptno from emp where ename='SMITH');
image-20230730195149621
image-20230730195149621

一样的道理,先通过SMITH找到对应的deptno,得到的这个deptno被当做约束条件查找对应的同一部门的员工。

2. 多行子查询

返回多行记录的子查询。即我们通过一个条件去寻找,能同时找到多个满足条件的数据,只要想要的数据在这多个数据中就显示。

  • **in关键字;**查询和10号部门的工作岗位相同的雇员的名字,岗位,工资,部门号,但是不包含10自己的
代码语言:javascript
复制
select ename, job, sal, deptno from emp where job in(select distinct job from emp where deptno=10) and deptno <> 10;
image-20230730200054593
image-20230730200054593
  • **all关键字;**显示工资比部门30的所有员工的工资高的员工的姓名、工资和部门号
代码语言:javascript
复制
select ename, sal, deptno from emp where sal > all(select sal from emp where deptno=30);
image-20230730200442353
image-20230730200442353

不用all,通过聚合函数max同样也可以满足要求

代码语言:javascript
复制
select ename, sal, deptno from emp where sal > (select max(sal) from emp group by deptno having deptno=30);
image-20230730200517515
image-20230730200517515
  • **any关键字;**显示工资比部门30的任意员工的工资高的员工的姓名、工资和部门号(包含自己部门的员工)

只要存在比部门30的任意员工工资高的,就显示。

代码语言:javascript
复制
select ename, sal, deptno from emp where sal > any(select sal from emp where deptno=30);
image-20230730200759124
image-20230730200759124

3. 多列子查询

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

即多个字段同时匹配,用括号将多个字段括起来,然后进行比较。

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

代码语言:javascript
复制
select * from emp where (deptno, job) = (select deptno, job from emp where ename='SMITH') and ename <> 'SMITH';
image-20230730201455183
image-20230730201455183

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

子查询语句出现在from子句中。这里要用到数据查询的技巧,把一个子查询当做一个临时表使用。即我们无论从什么时候通过条件或者查询所得到的的间接的表,都可以看做真正的表进行查询,因为,MySQL下一切皆表。

案例

  • 显示每个高于自己部门平均工资的员工的姓名、部门、工资、平均工资

对于每一个部门,显示的是高于自己部门平均工资的员工。

首先,将自己部门的平均工资筛选出来。

代码语言:javascript
复制
select deptno, avg(sal) from emp group by deptno;
image-20230730202611146
image-20230730202611146

将上一步的结果看成一张表,与emp表进行笛卡尔积,做完笛卡尔积,每一个员工根据部门的筛选,就都能对应自己部门的平均工资。

代码语言:javascript
复制
select * from emp, (select deptno, avg(sal) from emp group by deptno) tmp where emp.deptno = tmp.deptno;
image-20230730203123036
image-20230730203123036

接下来,就变成了普通的单表查询了,只需要在上面的这样表中,找到sal > avg(sal)的信息就可以了。

代码语言:javascript
复制
select ename, emp.deptno from emp, (select deptno, avg(sal) myavg from emp group by deptno) tmp where emp.deptno = tmp.deptno and emp.sal > tmp.myavg;
image-20230730205122923
image-20230730205122923

这也就得到了最终的结果。

若要显示这些人的办公地点,则只需要把上面的表与dept进行笛卡尔积,并通过dept一一对应,就可以得到最终结果

代码语言:javascript
复制
select t1.ename, dept.loc, t1.deptno from dept, (select ename, emp.deptno from emp, (select deptno, avg(sal) myavg from emp group by deptno) tmp where emp.deptno = tmp.deptno and emp.sal > tmp.myavg) t1 where t1.deptno = dept.deptno;
image-20230730205513202
image-20230730205513202

所以,面对非常复杂的查询问题,都可以将其进行分解,因为复杂的问题也都是由简单的问题复合而成的。

  • 查找每个部门工资最高的人的姓名、工资、部门、最高工资

看到部门,肯定就是聚合。聚合的结果只会有最高工资这个数字,姓名,工资都无法聚合。但是我们可以通过聚合得到的表(此表包含部门,最高工资)与emp表进行笛卡尔积,再筛选不对的信息,最后就又变成了单表查询。

先看看部门的最高工资:

代码语言:javascript
复制
select deptno, max(sal) max_sal from emp group by deptno;
image-20230730210101091
image-20230730210101091

得到的这张表与emp表进行笛卡尔积,筛选出对应的数据

代码语言:javascript
复制
select ename, sal, tmp.deptno, max_sal from emp, (select deptno, max(sal) max_sal from emp group by deptno) tmp where emp.deptno=tmp.deptno;
image-20230730211328004
image-20230730211328004

最后,再补充条件,emp.sal = tmp.max_sal

代码语言:javascript
复制
select ename, sal, tmp.deptno, max_sal from emp, (select deptno, max(sal) max_sal from emp group by deptno) tmp where emp.deptno=tmp.deptno and emp.sal = tmp.max_sal;
image-20230730211258577
image-20230730211258577

就得到了最终满足条件的结果。

  • 显示每个部门的信息(部门名,编号,地址)和人员数量
  1. 首先,人员数量一定是聚合出来的。
  2. 部门编号,地址,是在dept表中的

方法一:使用多表

将分组聚合得到的人员数量、部门表与dept表进行笛卡尔积,然后筛选对应信息,最后将得到的这个表再进行查询,得到我们最终需要的信息。

代码语言:javascript
复制
select t1.dname, t1.loc, t2.dept_num, t1.deptno from dept t1, (select deptno, count(*) dept_num from emp group by deptno) t2 where t1.deptno=t2.deptno;
image-20230730212806124
image-20230730212806124

方法二:子查询

代码语言:javascript
复制
-- 1. 对EMP表进行人员统计
select count(*), deptno from EMP group by deptno;
-- 2. 将上面的表看作临时表
select DEPT.deptno, dname, mycnt, loc from DEPT,
(select count(*) mycnt, deptno from EMP group by deptno) tmp
where DEPT.deptno=tmp.deptno;

实际上这与上面的形式一样,也是多表的范畴,因为MySQL下一切皆表,这种方式反而太过直接。

五.多表问题的指导思想

最后,通过我们上述的思考过程总结出 解决多表问题的本质:想办法将多表转化成单表,所以mysql中,所有select的问题全部都可以转化成单表问题!

六.合并查询

在实际应用中,为了合并多个select的执行结果,可以使用集合操作符 union,union all。

1. union

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

案例:将工资大于2500或职位是MANAGER的人找出来

image-20230731164016155
image-20230731164016155

2. union all

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

案例:将工资大于2500或职位是MANAGER的人找出来

image-20230731164138869
image-20230731164138869

union以及union all需要注意的是在连接时,两者显示的字段类型以及数量、位置必须完全一致,否则无法合并。

image-20230731164347070
image-20230731164347070
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-07-31,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一.基本查询回顾
  • 二.多表查询
  • 三.自连接
    • 1. 自连接的笛卡尔积
      • 2. 自连接案例
      • 四.子查询
        • 1. 单行子查询
          • 2. 多行子查询
            • 3. 多列子查询
              • 4. 在from子句中使用子查询
              • 五.多表问题的指导思想
              • 六.合并查询
                • 1. union
                  • 2. union all
                  相关产品与服务
                  云数据库 MySQL
                  腾讯云数据库 MySQL(TencentDB for MySQL)为用户提供安全可靠,性能卓越、易于维护的企业级云数据库服务。其具备6大企业级特性,包括企业级定制内核、企业级高可用、企业级高可靠、企业级安全、企业级扩展以及企业级智能运维。通过使用腾讯云数据库 MySQL,可实现分钟级别的数据库部署、弹性扩展以及全自动化的运维管理,不仅经济实惠,而且稳定可靠,易于运维。
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档