关联查询
概念
当在查询时,我们所需要的数据不在一张表中,可能在两张表或多张表中。此时我们需要同时操作这些表,即关联查询。
等值连接
在做多张表查询时,这些表中应该存在着有关联的两个字段,我们使用某一张表中的一条记录与另外一张表通过相关联的两个字段进行匹配,组合成一条记录。
笛卡尔积
在做多张表查询时,我们使用某一张表中的每一条记录与另一张表的所有记录进行组合
比如表A有x条,表B有y条,最终组合数为x*y,这个值就是笛卡尔积,通常没有意义。
内连接
只要使用了join on,就是内链接,查询效果与等值连接一样。
用法:表A [inner] join 表B on 关联条件【后再添加条件可以使用where也可以使用and】
外连接
在做多张表查询时,我们所需要的数据,除了满足关联条件的数据外,还有不满足关联条件的数据。此时需要使用外连接。会涉及到两个概念:
驱动表(主表):除了显示满足条件的数据,还需要显示不满足条件的数据的表
从表(副表):只显示满足关联条件的数据的表
外连接分类 左外连接 表A left [outre] join 表B on 关联条件。
表A是驱动表,表B是从表
右外连接 表A right [outer] join 表B on 关联条件。
表B是驱动表,表A是从表
全外连接 两张表的数据不管满不满足条件,都做显示。
表A full [outer] join 表B on 关联条件
PS:mysql不支持全外连接
自连接
在多张表进行关联查询时,这些表的表名是同一个。即自连接。
等值连接练习:查询部门表的名称及其每个部门的员工的员工编号和姓名及其职位,部门编号,按照部门号降序排序 |
select e.deptno,d.dname,e.empno,e.ename,e.job from emp e,dept d where e.deptno = d.deptno order by e.deptno DESC; |
内连接练习1:使用内连接修改上述练习 |
select dept.deptno,dname,empno,ename,job from emp join dept on emp.deptno = dept.deptno order by dept.deptno DESC; |
内连接练习2:查询20和30部门的部门名称,部门地址及其员工的姓名和工资 |
select emp.deptno,dname,loc,ename,sal+ifnull(comn,0) from emp join dept on emp.deptno = dept.deptno and emp.deptno in (20,30) order by emp.deptno ASC; |
左外连接练习:查询员工表的所有信息及其员工所在部门的信息 |
select emp.* ,dept.* from emp left join dept on emp.deptno = dept.deptno; |
右外连接练习:使用右外连接查询部门表的所有信息及其员工信息 |
select emp.*,dept.* from emp right join dept on emp.deptno = dept.deptno; |
全外连接练习:使用全外连接查询部门表的所有信息及其员工信息//mysql不支持全外连接 |
select emp.*,dept.* from emp full join dept on emp.deptno = dept.deptno; |
自连接练习1:查询员工的编号,姓名及其领导编号和姓名 |
select e1.empno "员工编号" ,e1.ename "员工姓名",e2.empno "领导编号" ,e2.ename "领导姓名" from emp e1 join emp e2 on e1.mgr = e2.empno or e1.mgr is null; |
自连接练习2:查询领导的姓名及其下属的姓名 |
select e1.ename "领导姓名",e2.ename "下属姓名" from emp e1 join emp e2 on e1.empno = e2.mgr and e2.mgr ; |
高级关联查询
有的时候我们要查询的数据,一个简单的查询语句满足不了,并且我们使用的数据,表中不能直观体现出来。
而是预先经过一次查询才会有所体现。那么先执行的查询,我们称之为子查询。被子查询嵌入的查询语句称之为父查询。
比如需求:查询工资大于员工JONES工资的员工的信息。
子查询返回的数据特点:
(1)可能是单行单列的数据。
(2)可能是多行单列的数据
(3)可能是单行多列的数据
(4)可能是多行多列的数据
1)子查询可以在where子句中
2)子查询可以在from子句中
3)子查询可以在having子句中
4)子查询可以在select子句中,相当于外连接中的另一种写法
子查询在where子句中 |
练习1:查询工资大于员工JONES工资的员工的信息 |
select * from emp where sal > (select sal from emp where ename = 'JONES'); |
练习2:查询员工表中工资大于10号部门的平均工资的员工的姓名,职位,工资及其部门号 |
select ename,job,sal,deptno from emp where sal > (select avg(ifnull(sal,0)) from emp where deptno = 10); |
练习3:查询工资等于每个部门的平均工资的人员信息 |
select * from emp where sal in (select avg(ifnull(sal,0)) from emp group by deptno) ; |
练习4:查询工资大于所有部门的平均工资的人员信息 |
select * from emp where sal >all (select avg(ifnull(sal,0)) from emp group by deptno) ; |
练习5:查询工资大于任意部门的平均工资的人员信息 |
select * from emp where sal >any (select avg(ifnull(sal,0))from emp group by deptno) ; |
练习6:先将clark和scott的奖金修改成300,查询工资和奖金与员工scott相同的其他员工信息 |
update emp set comn = 300 ; select * from emp where sal = (select sal from emp where ename = 'scott') and comn = (select comn from emp where ename = 'scott') and ename != 'scott'; select * from emp where (sal,comn) = (select sal,comn from emp where ename = 'scott') and ename != 'scott'; |
子查询在from子句中 |
练习1:查询每个员工的工资,姓名和其部门的平均工资。 |
第一步:查询每个部门部门的平均工资 |
select avg(ifnull(sal,0)) from emp group by deptno |
第二步:做关联查询(将上一步的查询语句看成一张表) |
select ename,sal,t.avg_ from emp e join (select deptno, avg(ifnull(sal,0)) 'avg_' from emp group by deptno) t on e.deptno = t.deptno ; |
练习2:查询大于本部门平均工资的员工的信息 |
select * from emp e join (select deptno, avg(ifnull(sal,0)) 'avg_' from emp group by deptno) t on e.deptno = t.deptno and e.sal>t.avg_; |
子查询在having子句中 |
练习1:查询部门平均工资小于10号部门平均工资的部门平均工资,工资之和,最大工资,最小工资,总人数 |
select avg(ifnull(sal,0)),sum(sal),max(sal),min(sal),count(*) from emp group by deptno having avg(ifnull(sal,0)) < (selectavg(ifnull(sal,0))from emp where deptno = 10); |
子查询在select子句中 |
练习1:查询每个员工的姓名,工资,及其部门的平均工资 |
select ename,sal,(select avg(ifnull(sal,0)) from emp a where a.deptno = b.deptno) avg_sal from emp b order by deptno ASC; //SUPERMAN 的平均工资是null,因为a.deptno= b.deptno 无法控制比较null |
练习2:查询每个员工的姓名,工资,及其部门的平均工资,工资之和 |
select ename,sal,(select avg(ifnull(sal,0)) from emp a where a.deptno = b.deptno) avg_sal ,(select sum(sal) from emp c where c.deptno = b.deptno) sum_sal from emp b order by deptno ASC; |