MySQL复合查询

MySQL复合查询

  • 一.基本查询回顾
  • 二.多表查询
  • 三.自连接
    • 1. 自连接的笛卡尔积
    • 2. 自连接案例
  • 四.子查询
    • 1. 单行子查询
    • 2. 多行子查询
    • 3. 多列子查询
    • 4. 在from子句中使用子查询
  • 五.多表问题的指导思想
  • 六.合并查询
    • 1. union
    • 2. union all

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

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

一.基本查询回顾

MySQL复合查询_第1张图片

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

MySQL复合查询_第2张图片

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

MySQL复合查询_第3张图片

  • 使用年薪进行降序排序

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

MySQL复合查询_第4张图片

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

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

MySQL复合查询_第5张图片

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

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

MySQL复合查询_第6张图片

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

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

MySQL复合查询_第7张图片

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

MySQL复合查询_第8张图片

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

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

MySQL复合查询_第9张图片

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

MySQL复合查询_第10张图片

二.多表查询

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

MySQL复合查询_第11张图片

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

MySQL复合查询_第12张图片

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

MySQL复合查询_第13张图片

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

MySQL复合查询_第14张图片

  • 显示各个员工的姓名,工资,及工资级别

MySQL复合查询_第15张图片

三.自连接

1. 自连接的笛卡尔积

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

直接连接是不对的:

image-20230730170205842

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

MySQL复合查询_第16张图片

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

2. 自连接案例

什么时候需要自连接呢?

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

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

MySQL复合查询_第17张图片

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

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

select e2.empno, e2.ename from emp e1, emp e2 where e1.ename='FORD' and e1.mgr=e2.empno;

image-20230730175821197

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

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

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

MySQL复合查询_第18张图片

四.子查询

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

1. 单行子查询

返回一行记录的子查询

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

  • 显示SMITH同一部门的员工
select * from emp where deptno = (select deptno from emp where ename='SMITH');

MySQL复合查询_第19张图片

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

2. 多行子查询

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

  • **in关键字;**查询和10号部门的工作岗位相同的雇员的名字,岗位,工资,部门号,但是不包含10自己的
select ename, job, sal, deptno from emp where job in(select distinct job from emp where deptno=10) and deptno <> 10;

MySQL复合查询_第20张图片

  • **all关键字;**显示工资比部门30的所有员工的工资高的员工的姓名、工资和部门号
select ename, sal, deptno from emp where sal > all(select sal from emp where deptno=30);

MySQL复合查询_第21张图片

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

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

image-20230730200517515

  • **any关键字;**显示工资比部门30的任意员工的工资高的员工的姓名、工资和部门号(包含自己部门的员工)

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

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

MySQL复合查询_第22张图片

3. 多列子查询

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

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

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

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

MySQL复合查询_第23张图片

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

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

案例

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

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

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

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

MySQL复合查询_第24张图片

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

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

MySQL复合查询_第25张图片

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

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;

MySQL复合查询_第26张图片

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

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

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;

MySQL复合查询_第27张图片

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

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

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

先看看部门的最高工资:

select deptno, max(sal) max_sal from emp group by deptno;

MySQL复合查询_第28张图片

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

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;

MySQL复合查询_第29张图片

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

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;

MySQL复合查询_第30张图片

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

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

  2. 部门编号,地址,是在dept表中的

方法一:使用多表

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

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;

MySQL复合查询_第31张图片

方法二:子查询

-- 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的人找出来

MySQL复合查询_第32张图片

2. union all

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

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

MySQL复合查询_第33张图片

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

MySQL复合查询_第34张图片

你可能感兴趣的:(MySQL,mysql,数据库)