Oracle作业5——多表查询、子查询

一、基础练习:

1.查询和scott相同部门的员工姓名ename和雇用日期hiredate

select ename,hiredate from emp where deptno=(select deptno from emp where ename='scott');

2.查询在部门的loc为new york的部门工作的员工的员工姓名ename,部门名称dname和岗位名称job

select e.ename,d.dname,e.job,d.loc from emp e,dept d where e.deptno=d.deptno and d.loc='new york';

3.查询上司是king的员工姓名(ename)和工资(sal)

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

4.查询与姓名中包含字母u的员工在相同部门的员工信息

select * from emp where deptno in(select deptno from emp where ename like '%u%');

5.查询所有雇员姓名和部门名称(使用left join,inner join, right join)

select e.ename,d.dname from emp e inner join dept d on e.deptno=d.deptno;
select e.ename,d.dname from emp e left join dept d on e.deptno=d.deptno;
select e.ename,d.dname from dept d right join emp e on e.deptno=d.deptno;

6.显示每个员工的员工姓名、部门名称、职务、工资、和工资等级信息(使用left join,inner join, right join)

select e.ename,d.dname,e.job,e.sal,s.grade from emp e inner join dept d on e.deptno=d.deptno inner join salgrade s on e.sal between s.losal and s.hisal;

select e.ename,d.dname,e.job,e.sal,s.grade from emp e left join dept d on e.deptno=d.deptno left join salgrade s on e.sal between s.losal and s.hisal;

select e.ename,d.dname,e.job,e.sal,s.grade from dept d right join emp e on e.deptno=d.deptno right join salgrade s on e.sal between s.losal and s.hisal;

二、综合练习

1.取得每个部门最高薪水的人员名称2.列出受雇日期早于其直接上级的所有员工的编号,姓名,部门名称

--使用相关子查询
select empno,ename,sal,deptno from emp e where e.sal=(select max(sal) from emp m where m.deptno=e.deptno) order by deptno;
--使用多表连接查询(渔舟唱晚同学的)
select empno,ename,sal,deptno from emp q, (select e.deptno 部门, max(e.sal) 最高薪资 from emp e group by e.deptno) 
r where r.部门 = q.deptno and q.sal = r.最高薪资 order by q.deptno;
--使用dense_rank()函数结合order by
select * from(select empno,ename,sal,deptno,dense_rank() over(partition by deptno order by sal desc)rn from emp) where rn=1 order by deptno;
--使用in子查询(有bug)
select empno,ename,deptno,sal from emp where sal in(select max(sal) from emp group by deptno) order by deptno;

--测试上面的in子查询bug:发现10部门的nullun也显示出来了,但其并非10部门最高工资,10部门最高工资为5000
insert into emp(empno,ename,deptno,sal) values(1015,'nullun',10,3000);
select empno,ename,deptno,sal from emp where sal in(select max(sal) from emp group by deptno) order by deptno;

2.列出受雇日期早于其直接上级的所有员工的编号,姓名,部门名称

--左自连接和多表查询
select e.empno 员工编号,e.ename 员工姓名,m.ename 主管姓名,e.hiredate 员工受雇日期, m.hiredate 上级雇用日期,d.dname 部门名称
from emp e,emp m,dept d where m.empno(+)=e.mgr and e.hiredate<m.hiredate and e.deptno=d.deptno order by e.empno;

--相关子查询和多表查询
select e.empno,e.ename,d.dname from emp e,dept d where e.hiredate
<(select hiredate from emp m where m.empno=e.mgr) and e.deptno=d.deptno order by e.empno;

3.列出所有”clerk”(办事员)的姓名及其部门名称,部门的人数

思路:1.先查询job为clerk的所有部门编号,将该子查询结果命名为a;2.再从emp表查询与a查询中部门编号相同的员工所在的部门人数,这一步的查询结果命名为b;3.最后从emp表、dept表和b查询中进行多表查询获取job为clerk的所有员工的姓名、部门名称和所在部门人数。

select e.ename,d.dname,t.部门人数,e.job from emp e,dept d,(select deptno,count(1) 部门人数 from emp where deptno in(
select distinct deptno from emp where job='clerk') group by deptno)t 
where e.deptno=d.deptno and e.job='clerk' and t.deptno=e.deptno;

4.列出与”scott”从事相同工作的所有员工及部门名称

select e.*,d.dname from emp e,dept d where e.job=(select job from emp where ename='scott') and e.deptno=d.deptno;

5.查出某个员工的上级主管,并要求出这些主管中的薪水超过3000

select e.empno 员工编号,e.ename 员工姓名,m.ename 主管姓名,m.sal 主管工资 from emp e,emp m where m.empno(+)=e.mgr and m.sal>3000;

6.找出部门10中所有经理(manager)和部门20中所有办事员(clerk)的详细资料

select e.*,d.dname,d.loc,s.* from emp e,dept d,salgrade s where e.deptno=d.deptno and e.sal between s.losal and s.hisal 
and (e.deptno=10 and e.job='manager' or e.deptno=20 and e.job='clerk'); --注意:e.deptno=10 and e.job='manager' or e.deptno=20 and e.job='clerk' 要用括号括起来,不然会与前面的and条件混淆造成错误!

7.找出早于12年前受雇的员工. 并且按受雇年份倒序排序

思路一:用months_between比较当前系统时间和受雇日期之前相差的月份,然后除以12,如果值大于12,则是早于12前受雇的员工。

--有错误的语句
select e.*,to_char(hiredate,'yyyy') 受雇年份,round((months_between(sysdate,hiredate)/12),2) 受雇年限 from emp e where 受雇年限>12 order by 受雇年份 desc; 
/*为什么“受雇年限”会是无效的标识符呢?因为select语句在where语句后面才执行,而列的别名(受雇年限)是在select时才生成的,故在where子句中看不到这个别名(受雇年限),自然无法引用这个别名了。*/

--排错后的正确语句
select e.*,to_char(hiredate,'yyyy') 受雇年份,round((months_between(sysdate,hiredate)/12),2) 受雇年限 from emp e 
where (months_between(sysdate,hiredate)/12)>12 order by 受雇年份 desc;

思路二:用add_months判断,(受雇日期+12*12)得出的日期如果小于当前系统时间,则是早于12前受雇的员工。

select e.*,to_char(hiredate,'yyyy') 受雇年份,add_months(hiredate,12*12) 受雇十二周年日,round((months_between(sysdate,hiredate)/12),2) 受雇年限 from emp e 
where add_months(hiredate,12*12)<sysdate order by 受雇年份 desc;
--注意:离当前日期越远的日期越小,反之,离当前日期越近的日期越大。

8.列出从事同一种工作但属于不同部门的员工的一种组合

--不算完美但算比较接近题意的sql语句
select distinct e.empno,e.ename,e.job,e.deptno from emp e,emp p where e.deptno!=p.deptno and e.job=p.job order by job,deptno;
--其它两种不等于的写法
select distinct e.empno,e.ename,e.job,e.deptno from emp e,emp p where e.deptno<>p.deptno and e.job=p.job order by job,deptno;
select distinct e.empno,e.ename,e.job,e.deptno from emp e,emp p where e.deptno^=p.deptno and e.job=p.job order by job,deptno;
/*精妙之处:使用distinct!如果不使用distinct,查询结果会出现很多一样的重复数据!*/

分析:为什么说上面的sql语句不算完美呢?因为从上图可看出job为clerk,且deptno=20的记录有两条,即分别是第2和第3条查询记录,这就与题目要求的“从事同一种工作但属于不同部门的员工”不一致了,故最理想的查询结果应该如下:

    

9.查询有奖金的所有员工的姓名、奖金以及所在部门名称

--如果奖金等于0也算有奖金,那如下实现:
select ename,comm,dname from emp e,dept d where comm is not null and e.deptno=d.deptno;

--如果奖金等于0不算有奖金,则如下实现:
select ename,comm,dname from emp e,dept d where comm is not null and comm<>0 and e.deptno=d.deptno;

10.给任职日期超过25年的员工加薪10%

select e.ename,e.sal 原薪水,e.sal*1.1 加薪后薪水,round((months_between(sysdate,hiredate)/12),2) 受雇年限 from emp e 
where (months_between(sysdate,hiredate)/12)>25;

 

 


 

(0)
上一篇 2022年3月22日
下一篇 2022年3月22日

相关推荐