Mysql之多表查询&子查询练习1

1. 查出至少有一个员工的部门。显示部门编号、部门名称、部门位置、部门人数。

列: d.deptno、d.dname、d.loc、部门人数
表: dept d,emp e
条件: 多表查询:使用关联列去除笛卡尔积: e.deptno = d.deptno

部门人数: select deptno,count(*) from emp group by deptno

SELECT d.deptno, d.dname,d.loc,z1.cnt
FROM (select deptno,count(*) cnt from emp group by deptno) z1 INNER JOIN dept d
on z1.deptno = d.deptno;

思想: 单独两部分都会剩下的采用链接!



2. 列出薪金比关羽高的所有员工。
列:*
表: emp
条件: 工资比关羽高--> 那关羽的工资是多高

分析:那关羽的工资是多高: select sal from emp where ename = '关羽'; 子查询的结果集是单行单列一般放在where后面作为条件!

select *
from emp 
where sal > (select sal from emp where ename = '关羽')




3. 列出所有员工的姓名及其直接上级的姓名。
列:e.ename,e2.ename
表  e,z1
条件: e.mgr = z1.empno

-- 
select e.ename '员工',z1.ename '上级' 
from emp e inner join (select empno,ename from emp) z1
on e.mgr = z1.empno

-- 上面还是有问题,是列出所有员工!
select e.ename '员工', m.ename '上级'
from emp e left outer join emp m
on e.mgr = m.empno;

思想: 自身多表连接

select * from emp;


4. 列出受雇日期早于直接上级的所有员工的编号、姓名、部门名称。
列:e.empno,e.ename,d.dname
表:emp e, emp m, dept d
条件:是上级并且受雇日期早于上级:e.mgr = m.empno and e.hiredate < m.hiredate,注意:

思路:先不查部门名称
select e.empno, e.ename,e.deptno
from emp e inner join emp m
on e.mgr = m.empno and e.hiredate < m.hiredate
注意:关联表时都需要一个列作为条件,不一定是从表的外键指向主表的主键,其他的也行,就行这里的e.mgr = m.empno 也行,为了去除笛卡尔积!

然后只剩部门名称了
select e.empno, e.ename,d.dname
from emp e inner join emp m inner join dept d
on e.mgr = m.empno and e.hiredate < m.hiredate and e.deptno = d.deptno;

-- 下面使用子查询的方式也可以完成,但sql过于复杂!
select z1.empno,z1.ename,d.dname
from (select e.empno empno, e.ename ename,e.deptno deptno
from emp e inner join emp m
on e.mgr = m.empno and e.hiredate < m.hiredate) z1 inner join dept d
on z1.deptno = d.deptno



5. 列出部门名称和这些部门的员工信息,同时列出那些没有员工的部门。
列:d.dname, e.*
表:emp e, dept d
条件: e.deptno = d.deptno 

select e.*, d.dname
from emp e right outer join dept d
on e.deptno = d.deptno


6. 列出所有文员的姓名及其部门名称,部门的人数。
列:e.ename,d.dname,部门人数
表: emp e, dept d
条件 e.deptno = d.deptno

注:部门人数: select deptno,count(*)  from emp group by deptno

思路:先简化一下,不要部门的人数
select e.ename,d.dname
from emp e inner join dept d
on e.deptno = d.deptno and e.job = '文员'; //使用标准内连接,有条件一般用and连上 !而不是where!

最后:
select e.ename,d.dname,z1.cnt
from emp e inner join dept d inner join (select deptno,count(*) cnt  from emp group by deptno) z1
on e.deptno = d.deptno and e.job = '文员' and d.deptno = z1.deptno;


7. 列出最低薪金大于15000的各种工作及从事此工作的员工人数。
列:e.job,员工人数
表:emp e
条件:最低薪金大于15000: min(sal) > 15000 : 只是这样表示而已!

思路:先简化一下,不要从事此工作的员工人数。
先根据部门编号分组,查看一下每个组中最低的工资是多少!
select deptno,min(sal)
from emp group by deptno

最后!
select e.ename,e.job, z2.cnt
from emp e inner join (select min(sal) minSal from emp group by deptno) z1 inner join (select job,count(*) cnt from emp group by job) z2
on e.deptno = z1.deptno and z1.minSal > 10000 and e.job = z2.job

判断:条件用在分组前还是分组后,看有没有聚合函数比如这里的min(sal) > 15000, 如果有就是在分组后
我这个分析有问题!

答案是这样的
select job,count(*)
from emp
group by job
having min(sal) > 15000


8. 列出在销售部工作的员工的姓名,假定不知道销售部的部门编号。
列:e.ename
表:emp e, dept d
条件:e.deptno = 销售部的编号 = (select deptno from emp where dname = '销售部')

列出在销售部工作的员工的姓名
方式一:子查询
select e.ename
from emp e
where e.deptno = (select deptno from dept where dname = '销售部')


方式二:连接查询
select e.ename
from emp e inner join dept d
on e.deptno = d.deptno and d.dname = '销售部'




9. 列出薪金高于公司平均薪金的所有员工信息,所在部门名称,上级领导,工资等级。
列:e.*, d.dname, 上级领导,工资等级
表:emp e, emp m,dept d
条件: 高于公司平均薪金 sal>avg(sal)

select e.ename,e.sal,d.dname, m.ename '上级'
from emp e inner join dept d inner join emp m
on e.deptno = d.deptno and e.mgr = m.empno and e.sal>(select avg(sal) from emp)

我上面写法不是很好,应该连接一张表就给出条件,应该如下:
select e.*,d.dname,m.ename '上级',s.grade
from 
		emp e left outer join dept d on e.deptno = d.deptno
          left outer join emp m  on e.mgr = m.empno
          left outer join salgrade s on e.sal between s.losal and s.hisal
where e.sal > (select avg(sal) from emp)          


使用方言写一遍:
select e.*,d.dname,m.ename '上级',s.grade
from emp e,dept d,emp m,salgrade s
where e.deptno = d.deptno and e.mgr = m.empno and e.sal between s.losal and s.hisal and e.sal > (select avg(sal) from emp)

总结:标准是一个连接一个条件,方言是先全部连接,后全部条件
      标准是一个饺子粘点酱吃,方言是先把饺子吃完,再把酱喝完!


10.列出与庞统从事相同工作的所有员工及部门名称。
列:e.ename,d.dname
表:emp e, dept d
条件:庞统从事相同工作--> 庞统是什么工作--> select job from emp where ename = '庞统'

select e.ename,e.job,d.dname
from emp e inner join dept d
on e.deptno = d.deptno and job = (select job from emp where ename = '庞统') 

11.列出薪金高于在部门30工作的所有员工的薪金的员工姓名和薪金、部门名称。
列:e.ename,e.sal,d.dname
表:emp e,dept d
条件:sal > (30部门最高工资) = select max(sal) from emp where deptno = 30;

select e.ename,e.sal,d.dname
from emp e inner join dept d on e.deptno = d.deptno
where e.sal > (select max(sal) from emp where deptno = 30)

//这样也行
select e.ename,e.sal,d.dname
from emp e inner join dept d on e.deptno = d.deptno
where e.sal > all (select sal from emp where deptno = 30)


12.列出每个部门的员工数量、平均工资。
select * from emp
列:count(*),avg
表:emp e
条件:

select deptno,count(*),avg(sal)
from emp
group by deptno

注: 一旦group by,那么group by后面列名,会出现在select后,其他列名出现会有错误,除非聚合函数包着!

13.查出年份、利润、年度增长比
今年的增长比 = 今年的增长-去年的增长/去年的增长
所以要找到一行记录,有今年的增长,去年的增长

create table tb_year(
	year int primary key auto_increment,
  zz int
);

insert into tb_year values(2010,100);
insert into tb_year values(null,150);
insert into tb_year values(null,250);
insert into tb_year values(null,800);
insert into tb_year values(null,1000);

select * from tb_year


select t1.*, ifnull(concat((t1.zz - t2.zz)/t2.zz*100,'%'),'0%') '年度增长比'
from tb_year t1 left outer join tb_year t2
on t1.year = t2.year+1







1. 查出至少有一个员工的部门。显示部门编号、部门名称、部门位置、部门人数

dept表: 部门编号、部门名称、部门位置
emp表: 部门人数

-- 方式一: 先表之间连接,再过滤内容
SELECT
	d.dname, d.loc, d.deptno,count(e.deptno) as deptCount
from 
	dept d 
inner join 
	emp e
on
	d.deptno = e.deptno
group by
	e.deptno
having 
	count(*) > 1


-- 方式二:先得的每个表的数据,表与表之间再连接
SELECT
	d.deptno, d.dname, d.loc, temp.deptCount
FROM
	dept d
inner join 
(
SELECT
	count(deptno) as deptCount, deptno
FROM
	emp
GROUP BY
	deptno
having 
	count(deptno) > 1
) temp
on
	d.deptno = temp.deptno

-- 方式二的简洁写法: 在子查询多且复杂的时候能体现出来优势
with temp as(
	select deptno, count(*) as deptCount from emp group by deptno having count(*) > 1
)
select 
	d.dname, d.loc, d.deptno, temp.deptCount
from 
	dept d inner join temp on d.deptno = temp.deptno


=========================================================================================4.列出受雇日期早于直接上级的所有员工的编号、姓名、部门名称。
select 
	e.ename, 
	e.hiredate as '员工受雇日期', 
	t.ename as '上级领导',
	t.hiredate as '上级领导的受雇日期'
from 
	emp e
inner join emp t on e.mgr = t.empno where e.hiredate < t.hiredate
inner join dept d  on e.deptno = d.deptno
注:这种写法是错误的例子


-- 方式一: 先表之间连接,再过滤内容,一次性查出来不需要子查询
-- 这种多表连的话, on只能有一个,表与表之间去除笛卡尔积的条件用and连起来, 过滤的用where
select 
	e.ename, 
	e.hiredate as '员工受雇日期', 
	t.ename as '上级领导',
	t.hiredate as '上级领导的受雇日期'
from 
	emp e 
inner join 
	emp t 
inner join 
	dept d 
on 
	e.mgr = t.empno and e.deptno = d.deptno
where 
	e.hiredate < t.hiredate
	
-- 方式二:分两步走,分别把数据查出来,再连接表
-- 1.列出受雇日期早于直接上级的所有员工的编号、姓名
select 
	e.empno, e.ename, e.deptno
from 
	emp e
inner join 
	emp m
on 
	e.mgr = m.empno
where
	e.hiredate < m.hiredate

-- 2.部门表
select
	d.* 
from 
	dept d 


select 
	d.*, temp.empno, temp.ename
from 
	dept d
inner join
(
select 
	e.empno, e.ename, e.deptno
from 
	emp e
inner join 
	emp m
on 
	e.mgr = m.empno
where
	e.hiredate < m.hiredate
) temp 
on temp.deptno = d.deptno

-- 稍微简洁点,看的很清楚
with e as(
	select 
		e.empno, e.ename, e.deptno
	from 
		emp e
	inner join 
		emp m
	on
		e.mgr = m.empno
	where
		e.hiredate < m.hiredate
)
select 
	*
from 
	dept d inner join e
on 
	d.deptno = e.deptno

	

 

  • 5
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值