有时候我们要查找的信息在两个表里,还是拿经典测试表举例。
现在想筛选出相同部门的员工,并显示它们的员工名,部门号和部门名。
我们发现,员工名和部门号都在emp这张表中,但是部门名在dept这张表。因此我们要进行多表查询。
多表查询的语法很简单,就是from后面接不同的表名即可。
from a, b, c, ...
mysql中select * from a, b,c返回的时候是怎么返回的呢?
最终返回的表如图:这种叫笛卡尔积。
因此要在多表查询中查到我们想要的信息,就必须要进行筛选。
回到刚刚那个题目:
我们首先需要筛选的信息就是emp表的deptno应该要等于dept表的deptno,因为一个员工不可能既是A部门,又是B部门。
加上where emp.deptno = dept.deptno
即可
需要说的就是由于多表中有可能有很多相同名字的列,比如emp表有deptno,dept表也有deptno。因此为了防止混淆,用表名.列来区分
工资只能是一个级别的,因此用工资来筛选即可。
工资在级别对于的范围,就符合条件。
sal between losal and hisal
所谓自连接就是自己和自己笛卡尔积之后得到的表
例子:
显示员工FORD的上级领导的编号和姓名(mgr是员工领导的编号–empno)
有两种方法:
1.直接查
筛选条件就是ford的mgr编号等于empno
2.用自连接
注:这里不能加上a.empno = b.empno,加上了自连接就白连了,又变回单表了
嵌套查询有多行单列和单行多列。
之前写的全是这种单行子查询
单行子查询是指第二个select返回一行的记录
举个例子:
select * from EMP WHERE deptno = (select deptno from EMP where ename=‘smith’);
第二个select其实就是把ename = smith的那一行返回了。
后面的select返回多行单列记录。
相当于返回了一个集合,然后再从这个集合当中选数据。用三个关键字选,分别是in,all,any
查询和10号部门的工作岗位相同的雇员的名字,岗位,工资,部门号,但是不包含10自己的
相当于从集合(所有10号部门的工作岗位)中挑选数据。怎么挑选呢?
挑选那些工作和集合内元素相同的人。
最后再把属于集合内的人筛掉即可。
显示工资比部门30的所有员工的工资高的员工的姓名、工资和部门号
显示工资比部门30的任意员工的工资高的员工的姓名、工资和部门号(包含自己部门的员工)
子查询一定是返回单行,否则会报错的。
语法(多列数据) = (多列数据)
查询和SMITH的部门和岗位完全相同的所有雇员,不含SMITH本人
子查询是集合,集合其实就是一张表。因此可以让from从表中查找数据
模板:
select xxxx from xxx (select xxx,xxx from xxx group by xxx) where xxx
例子:显示每个高于自己部门平均工资的员工的姓名、部门、工资、部门平均工资
这个题挺难的。
先说答案:
select ename, deptno, sal, asal from EMP,
(select avg(sal) asal, deptno dt from EMP group by deptno) tmp
where EMP.sal > tmp.asal and EMP.deptno=tmp.dt;
由于要求平均工资,因此要用avg函数,由于avg函数是聚合函数,聚合函数只有一行,不能和这些多行的数据放在同一张表里面。
因此要求avg必须得根据部门号去group by deptno求,并生成一张新表。再从这两张新表多表查询,筛选出答案。
需要注意的一点是,前面select 必须写成asal,不能写成avg(sal).原因就是刚刚说的avg是聚合函数,不能直接这么用。
第二道题目:查找每个部门工资最高的人的姓名、工资、部门、最高工资
select EMP.ename, EMP.sal, EMP.deptno, ms from EMP,
(select max(sal) ms, deptno from EMP group by deptno) tmp
where EMP.deptno=tmp.deptno and EMP.sal=tmp.ms;
这道题和上面是一样的。
第三道题目:显示每个部门的信息(部门名,编号,地址)和人员数量
select dname, deptno, loc, cnt from dept,
(select deptno dt, count(deptno) cnt from emp group by deptno) tmp where dept.deptno = tmp.dt;
其实可以说都是同样的模板了。
对两个集合求并集,会自动去掉结果集中的重复行。
将工资大于2500或职位是MANAGER的人找出来
语法
select 字段 from 表1 inner join 表2 on 连接条件 and 其他条件;
SQL查询中各个关键字的执行先后顺序 from > on> join > where > group by > with > having > select > distinct > order by > limit。
where写法
select ename, dname from EMP, DEPT where EMP.deptno=DEPT.deptno and ename=‘SMITH’;
on写法
select ename, dname from EMP inner join DEPT on EMP.deptno=DEPT.deptno where ename=‘SMITH’;
(用on就一定要用inner join)
关于on和where的区别:我们可以发现on的执行顺序要先于where,因此我们可以理解成,在进行笛卡尔积的时候,如果用on进行连接的话,on并没有让两个表全部连接,而是只把正确的部分连接起来了。
如果使用where的话,它做的是筛选的工作。表是被完整的连接出来之后,根据where的条件来筛选出结果的。
注:前面写的from a, b就是内连接,只不过是全内连接
分为左外连接和右外连接
如果联合查询,左侧的表完全显示我们就说是左外连接
select 字段名 from 表名1 left join 表名2 on 连接条件
使用场景:比如一场考试,有一张学生表,一张考试成绩表(没有成绩的同学不在里面),现在要显示所有学生的成绩信息。(包括没成绩的)
如果使用
select stu.id, name, score from stu inner join exam on stu.id = exam.id
看起来好像没什么问题,但是如果exam表里面没有成绩的同学就不存进去了,那么使用内连接的话,没有成绩的同学就无法显示出来了。
这个时候就要使用左外连接了,保证所有学生的信息都要显示出来。
select stu.id, name, score from stu left join exam on stu.id = exam.id
右连接是同理的。
列出部门名称和这些部门的员工信息,同时列出没有员工的部门
分析:很明显是dept表和emp表连接,它又要求同时列出没有员工的部门,因此要把dept变成左连接,保证全部显示。