oracle 学习笔记
–单行子查询:返回一行一列的值,使用单行运算符: < <= > >= <> =
显示和雇员7369从事相同工作并且工资大于雇员7876的雇员
的姓名和工作
SELECT ename, job
FROM emp
WHERE job=(
SELECT job FROM emp WHERE empno=7369
)
AND sal>(
SELECT sal FROM emp WHERE empno=7876
);
子查询中使用组函数
– 查询工资最低的员工姓名,岗位及工资
select ename,job,sal
from emp
where sal=(
select min(sal) from emp
);
HAVING子句中使用子查询
– 查询部门最低工资比20部门最低工资高的部门编号及最低工资
select deptno,min(sal)
from emp
group by deptno
having min(sal)>(
select min(sal) from emp
group by deptno
having deptno=20
);
– 查询哪个部门的员工人数高于各部门平均人数。
select deptno,count(empno)
from emp
group by deptno
having count(empno)>(
select avg(count(empno))
from emp
group by deptno
);
练习1
1.查询入职日期最早的员工姓名,入职日期
select ename,hiredate
from emp
where hiredate = (select min(hiredate) from emp );
2.查询工资比SMITH工资高并且工作地点在
CHICAGO的员工姓名,工资,部门名称
select e.ename,e.sal,d.dname
from emp e,dept d
where e.deptno=d.deptno and d.loc=’CHICAGO’
and e.sal > (select sal from emp where ename=’SMITH’);
3.查询入职日期比20部门入职日期最早的员工还
要早的员工姓名,入职日期
select ename,hiredate
from emp
where hiredate < (
select min(hiredate) from emp where deptno=20
);
4.查询部门人数大于所有部门平均人数的的部门
编号,部门名称,部门人数
select deptno,count(1)
from emp
group by deptno
having count(1) > (
select avg(count(1)) from emp group by deptno
);
–多行子查询:返回多行一列的值,使用多行运算符:in any all
–IN使用
– 查询是经理的员工姓名,工资
select ename,sal
from emp
where empno in(
select mgr from emp
);
–ANY的使用
– 查询是经理的员工姓名,工资。
select ename,sal
from emp
where empno = any (
select mgr from emp
);
– 查询部门编号不为10,且工资比10部门任意一名员工工资
高的员工编号,姓名,职位,工资。
select empno,ename,job,sal,deptno
from emp
where sal > any(
select sal from emp where deptno=10
)
and deptno<>10;
–ALL的使用
– 查询部门编号不为10,且工资比10部门所有员工工资高的
员工编号,姓名,职位,工资。
select empno,ename,job,sal,deptno
from emp
where sal > all(
select sal from emp where deptno=10
)
and deptno<>10;
练习
1.查询入职日期比10部门任意一个员工晚的员工姓名、入职日期,不包括10部门员工
select ename,hiredate,deptno
from emp
where hiredate > any (
select hiredate from emp where deptno=10
) and deptno<>10;
2.查询入职日期比10部门所有员工晚的员工姓名、入职日期,不包括10部门员工
select ename,hiredate,deptno
from emp
where hiredate > all (
select hiredate from emp where deptno=10
) and deptno<>10;
3.查询职位和10部门任意一个员工职位相同的员工姓名,职位,不包括10部门员工
select ename,job
from emp
where job in (
select job from emp where deptno=10
);
–多列子查询:返回多行多列的值,使用多行运算符:in
• 查询出和1981年入职的任意一个员工的部门和
职位完全相同员工姓名、部门、职位、入职日
期,不包括1981年入职员工。
select ename,deptno,job,hiredate
from emp
where (deptno,job) in (
select deptno,job from emp where to_char(hiredate,’YYYY’)=’1981’
)
and to_char(hiredate,’YYYY’)<>’1981’;
• 查询出和1981年入职的任意一个员工的部门或
职位相同员工姓名、部门、职位、入职日期,不
包括1981年入职员工。
select ename,deptno,job,hiredate
from emp
where (deptno in (
select deptno from emp where to_char(hiredate,’YYYY’)=’1981’
)
or job in (
select job from emp where to_char(hiredate,’YYYY’)=’1981’
))
and to_char(hiredate,’YYYY’)<>’1981’;
练习 3
1.查询职位及经理和10部门任意一个员工职位及经理相同的员工姓名,职位,不包括10部门员工
select ename,job,mgr
from emp
where (job,mgr) in
(select job,mgr from emp where deptno=10)
and deptno <> 10;
select job,mgr from emp where deptno=10;
2.查询职位及经理和10部门任意一个员工职位或经理相同的员工姓名,职位,不包括10部门员工
select ename,job,mgr
from emp
where (job in
(select job from emp where deptno=10)
or mgr in (select mgr from emp where deptno=10))
and deptno <> 10;
子查询中空值处理
因为子查询的结果中有一条空值,这条空值导致主查询没有记录返回。这
–是因为所有的条件和空值比较结果都是空值。因此无论什么时候只要空值
有可能成为子查询结果集合中的一部分,就不能使用NOT IN 运算符。
查询不是经理的员工姓名。
select ename,sal
from emp
where empno not in (
select mgr from emp
);–错误
–在 from 子句中使用子查询
–查询结果返回作为临时表
• 查询比自己部门平均工资高的员工姓名,工资,
部门编号,部门平均工资
select a.ename,a.sal,a.deptno,b.salavg
from emp a,(select deptno,avg(sal) salavg
from emp
group by deptno) b
where a.deptno = b.deptno
and a.sal>b.salavg;
练习4
• 1.查询比自己职位平均工资高的员工姓名、职位
,部门名称,职位平均工资
select e.ename,e.job,e.deptno,d.dname,e.sal,a.salavg
from emp e,dept d,(select job,avg(sal) salavg from emp group by job) a
where e.deptno=d.deptno and e.job=a.job and e.sal > a.salavg;
• 2.查询职位和经理同员工SCOTT或BLAKE完全相同
的员工姓名、职位,不包括SCOOT和BLAKE本人。
select ename,job
from emp
where (job,mgr) in (select job,mgr from emp where ename in (‘SCOTT’,’BLAKE’))
and ename not in (‘SCOTT’,’BLAKE’);
select job,mgr from emp where ename in (‘SCOTT’,’BLAKE’);
• 3.查询不是经理的员工姓名
select ename
from emp
where empno not in (select mgr from emp where mgr is not null); –注:所有的条件和空值比较结果都是空值
–rownum 查询
– ROWNUM使用的注意点:
–rownum 伪列:永远从1开始,不能使用>,=,>=,between..and区间运算做比较运算,只能使用<或者<=
select rownum,e.* from emp e where rownum<=3;
select rownum,e.* from emp e order by rownum desc;–rownum可以与order by结合使用
–rowid 伪列,物理存在,唯一标识每一行数据,可以通过rowid修改数据或删除数据
select rowid,e.* from emp e where rowid=’AAAR3sAAEAAAACXAAH’; –AAAR3sAAEAAAACXAAB
–• 2.ROWNUM和ORDER BY一起使用时,因为ROWNUM在记录输出时
–生成,而ORDER BY子句在最后执行, 所以当两者 一 起使用时,
–需要注意ROWNUM实际是已经被排了序的ROWNUM。
select * from emp where rownum > 7;
–TOP-N查询:查询指定某列前N条数据
select * from (select e.*,rownum rn
from (select * from emp order by sal asc) e)
where rn>3 and rn <6;
select * from emp order by sal asc;
练习5
• 1.查询入职日期最早的前5名员工姓名,入职日
期。
select ename,hiredate,rownum
from (select * from emp order by hiredate asc)
where rownum < 6;
• 2.查询工作在CHICAGO并且入职日期最早的前2名
员工姓名,入职日期。
select a.ename,a.hiredate,a.loc,rownum rn
from (select ename,hiredate,d.loc from emp e,dept d where e.deptno=d.deptno and d.loc=’CHICAGO’
order by hiredate
) a
where rownum < 3;
• 3.查询入职日期最早的第四和第五名员工姓名,入职日
期。
select * from (select e.*,rownum rn
from (select * from emp order by hiredate asc) e)
where rn>3 and rn <6;
–分页查询
–查询第二页的员工信息,每页三条数据
开始>每页条数*(当前页-1)
结束<= 当前页*每页条数
已知:每页显示5条,当前页数1
1 1-5
2 6-10
3 11-15
4 16-20
开始索引:(当前页码每页显示条数)-每页显示条数 + 1 = (当前页码-1)每页显示条数+1
结束索引:当前页码*每页显示条数
select * from (
select e.*,rownum rn from (
select empno,ename,deptno from emp order by empno asc
) e where rownum<= 3*2
)
where rn > 3*(2-1); –效率比较高
select * from (
select e.*,rownum rn from (
select empno,ename,deptno from emp order by empno asc
) e
)
where rn>3*(2-1) and rn <= 3*2;
练习7
• 1.按照每页显示5条记录,分别查询工资最高的
第1页,第2页,第3页信息,要求显示员工姓名
、入职日期、部门名称、工资。
select * from (
select e.*,rownum rn
from (select * from emp order by sal desc) e
where rownum <=&endindex —&endindex: 动态变量
)
where rn>&startindex;
–嵌套子查询
• 在通常的子查询中,子查询是以嵌套的方式写在
父查询的WHERE、HAVING、FROM子句中,所以被
称为嵌套子查询
例:思考如何查询比本部门平均薪水高的员工姓
名,薪水
select e.ename,e.sal,s.deptno
from emp e,(
select deptno,avg(sal) avgsal from emp group by deptno
) s
where e.deptno=s.deptno and e.sal>s.avgsal;
–相关子查询
• 相关子查询:当子查询中引用了父查询表中的一个
列时,Oracle服务器执行相关子查询。
• 相关子查询的执行过程:
– 1.取得父查询的候选行;
– 2.用候选行被子查询引用列的值执行子查询;
– 3.用来自子查询的值确认或取消候选行;
– 4.重复步骤1、2、3,直到父查询中无剩余的候选行。
–在WHERE子句中使用相关子查询;
select deptno,ename,sal
from emp e
where sal > (select avg(sal) from emp where deptno=e.deptno);
• 例:查询所有部门名称和人数
select d.deptno,d.dname,count(e.empno)
from emp e,dept d
where e.deptno(+)=d.deptno
group by d.deptno,d.dname;
–在SELECT子句中使用相关子查询;
select d.deptno,d.dname,(
select count(empno) from emp where deptno=d.deptno
)
from dept d;
• 例:查询哪些员工是经理?
select mgr.empno,mgr.ename
from emp mgr
where 0 = (select count(*) from emp where mgr.empno=mgr );
–EXISTS 和 NOT EXISTS
– EXISTS判断是否“存在”,具体操作如下:
• 子查询中如果有记录找到,子查询语句不会继续执行,
返回值为 TRUE;
• 子查询中如果到表的末尾也没有记录找到,返回值为 FALSE
• 例:查询哪些员工是经理?
select mgr.empno,mgr.ename
from emp mgr
where not exists (select ‘1’ from emp where mgr.empno=mgr );
课后作业
• 如下练习,使用相关子查询完成。
• 1.查询薪水多于他所在部门平均薪水的雇员名字,部门号。
select e.ename,e.deptno,e.sal
from emp e
where e.sal > (
select avg(sal) avgsal from emp where e.deptno=deptno
) ;
• 2.查询员工姓名和直接上级的名字。
select e.ename “员工姓名”,(select ename from emp where e.mgr=empno) “经理姓名”
from emp e;
• 3.查询每个部门工资最高的员工姓名,工资。
select deptno,ename,sal
from emp e
where e.sal in (select max(sal) from emp group by deptno); –嵌套查询
SELECT *
FROM emp e
WHERE (SELECT COUNT(empno) FROM emp WHERE deptno=e.deptno AND sal>e.sal)<=0 –相关子查询
• 4.查询每个部门工资前两名高的员工姓名,工资。
select rownum rn,e.deptno,e.ename,e.sal
from (select deptno,ename,sal
from emp
where deptno=d.deptno
order by sal desc) e
where rownum<3;
SELECT *
FROM emp e
WHERE (SELECT COUNT(empno)FROM emp WHERE
deptno=e.deptno AND sal>e.sal)<=1;
层次查询
–遍历树 :从底向上
select empno,ename,job,mgr
from emp
start with empno=7876
connect by prior mgr=empno;
–遍历树:从顶向下
select ename || ’ reports to ’ ||
prior ename “Walk Top Down”
from emp
start with ename=’KING’
connect by prior empno=mgr;
用 用 LEVEL 伪列将行分等级
select level,empno,ename,job,mgr
from emp
start with ename=’KING’
connect by prior empno=mgr
order by level;
SELECT LPAD(ename, LENGTH( ename )+(LEVEL*2)-2,’*’)
AS org_chart
FROM emp p
START WITH ename=’KING’
CONNECT BY PRIOR empno=mgr;