一、基本的查询回顾练习
前面两章节整理了许多关于查询用到的语句和关键字,以及MySQL的内置函数,我们先用一些简单的查询练习去回顾之前的知识
1. 前提准备
同样是前面用到的用于测试的表格和数据,一张学生表和三张关于雇员信息表
雇员信息表
2. 测试样例
2.1 查询工资高于500或岗位为MANAGER的雇员,同时还要满足他们的姓名首字母为大写的J
2.2 按照部门号升序而雇员的工资降序的排序
2.3 显示工资最高的员工名字和岗位
2.4 显示工资高于平均工资的人
同样是利用子查询,先算到平均工资是多少,然后条件筛选出高于该工资的人
2.5 显示每个部门的平均工资和最高工资
要不同部门的显示平均工资和最高工资,也就是要按部门先分组,再聚合
2.6 显示平均工资低于2000的部门号和它的平均工资
首先,我们要显示的是部门号和它的平均工资,要求是部门平均工资低于2000,因此还要得到各个部门的平均工资,并且进行条件筛选
2.7 显示每种岗位的雇员总数,平均工资
根据要求,应该要显示岗位、岗位雇员总数、平均工资,需要按岗位分组,聚合
二、多表查询
在实际开发中,往往要描述一些较为复杂的系统时,往往数据不止被记录在一张表格内,例如我们一直在使用的雇员信息表,就有三张,因此我们还需要多表进行查询
先介绍一个概念——笛卡尔积
笛卡尔积本质就是一种穷举的策略,在对两个表进行联合查询的时候,实际就是表一的第一条记录和表二的所有记录进行拼接,然后是表一第二条记录和表二的所有记录拼接,以此类推形成新表,这种穷举拼接的策略就是两个表的笛卡尔积
我们在需要用到多个表的数据时,联合查询会得到多个表的笛卡尔积,在其中通过条件筛选出我们需要的数据,就是多表查询,接下来还是利用雇员信息表来练习多表查询
1. 显示雇员名、雇员工资以及所在部门的名字
雇员名字和雇员工资在emp表中,而部门名字在dept表中,因此需要联合查询
2. 显示部门号为10的部门名,员工名和工资
首先我们需要显示部门名,员工名,还有工资,需要联合查询,然后是条件筛选出部门号为10的
3. 显示各个员工的姓名,工资,及工资级别
需要显示的是员工名字,工资和工资级别,因此要用到emp和salgrade这两个表
三、自查询
自查询实际就是一个表自己和自己的笛卡尔积,这种查询方式也有一定的应用场景,要注意,由于两个表都是同一张,因此命名上会有冲突,需要对表的名字进行重命名
应用场景
显示员工FORD的上级领导的编号和姓名
我们要找到员工FORD的领导信息,可以通过FORD信息中的领导编号去找到领导的信息,可以使用子查询的方式先找到FORD的领导编号,再找领导信息,同时也可以使用自查询的方式,去条件筛选出领导的信息
四、子查询
子查询在前面一些例子中已经用到过了,接下来详细整理和说明子查询
1.单行子查询
单行子查询就是前面用到的,子查询结果返回单行记录的情况
例子:显示SMITH同一部门的员工
首先我们要通过子查询先找到SMITH所属的部门,再进行条件筛选
2.多行子查询
当子查询返回结果为多行记录时,条件筛选的条件是一个集合,此时我们针对不同的情况,有三个关键字in、all、any去链接筛选条件:
in:表示筛选出该条件集合中的数据
all:表示前面的表达式需要满足和该集合中所有元素都作用且为true才符合筛选条件
any:表示前面的表达式和该集合中的元素任意一个满足条件即可符合筛选条件
例子:
a. 查询和10号部门的工作岗位相同的雇员名字、岗位、工资、部门号,但不包含10号本身
分析:要显示的是ename、job、sal、deptno,筛选条件是和部门号10相同的岗位,需要先找到和十号部门相同的岗位集合,条件是岗位是该集合其中一个即可符合条件,因此使用in,同时要去掉十号本身
b. 显示工资比部门30的所有员工的工资高的员工的名字、工资和部门号
分析:要显示的是员工名字、工资、部门号,条件是比部门30所有员工工资要高,我们可以选择找到该部门工资最高为多少,但这里为了示范all的使用,我们采用另一种思路,我们先找到30号部门所有员工工资的集合,然后筛选条件为大于该集合中的所有元素,因此用all
c. 显示工资比部门30的任意员工的工资高的员工的姓名、工资和部门号(结果包括部门30的人)
分析:显示ename、sal、deptno,要求比部门30的任意员工工资都高,先子查询找到该部门工资的集合,条件筛选是大于该部门的任意一人,因此使用any连接条件
3.多列子查询
子查询返回的结果为多列数据时就叫多列子查询
案例:查询和SMITH的部门和岗位完全相同的所有雇员,不含SMITH本人
分析:条件是和SMITH的部门和岗位都完全相同,因此需要先找到SMITH的岗位和部门是什么,该子查询返回结果是两列的,此时返回的结果的格式要认为是(v1,v2,...)这种类型,在做条件判断时,左侧也应该是这种格式
4.在from子句中使用子查询
我们可以将子查询的结果看作一张临时表,子查询的结果同样可以放在from后面去满足一些查询要求
案例:
a.显示每个高于自己部门平均工资的员工的姓名、部门、工资、平均工资
分析:先通过分组子查询可以查到各个部门的部门平均工资,然后可以对emp和子查询结果进行笛卡尔积,这样每个员工信息后面都附加上了其所在部门的平均工资,然后再条件筛选即可
select ename,emp.deptno,sal,avg_sal from emp,(select deptno,avg(sal) as avg_sal from emp group by deptno) as tmp where emp.deptno=tmp.deptno and emp.smp.sal>tmp.avg_sal;
b. 查找每个部门工资最高的人的姓名、工资、部门、最高工资
分析:先子查询到每个部门的最高工资,然后再和emp笛卡尔积得到新表进行筛选
select ename,sal,deptno,max_sal from emp,(select deptno dt,max(sal) max_sal from emp group by deptno) tmp where emp.deptno=tmp.dt and emp.sal=tmp.max_sal;
c. 显示每个部门的信息(部门名、编号、地址)和人员数量
分析:我们先将需要的信息都查询出来,我们需要每个部门的部门名、编号以及地址,这些信息都在dept表上,人员数量则是对emp表格中根据部门不同分组然后聚合
select dept.deptno,dept.dname,dept.loc,num from dept,(select deptno,count(*) as num from emp group by deptno) as tmp where dept.deptno=tmp.deptno;
5.合并查询
在实际应用中,为了合并多个select的查询结果,可以使用集合操作符 union 和 union all
(1)union
该操作符用于取得两个结果集的并集,当使用该操作符时,会自动去掉结果集中的重复行。
案例:将工资大于2500或职位是MANAGER的人找出来
(2)union all(不去重)
该操作符用于取得两个结果集的并集,当使用该操作符时,不会去掉结果集中的重复行。
案例:将工资大于2500或职位是MANAGER的人找出来
总结
本篇更进一步的整理介绍了查询的操作,对一些复杂的情况进行各种复合查询的操作,以及提供了大量的练习和样例