Oracle-SQL开发 —— 子查询
原创约 3841 字大约 13 分钟...
子查询.md
53-Oracle-SQL开发 ——注意
本博文仅供学术研究和交流参考,严禁将其用于商业用途。如因违规使用产生的任何法律问题,使用者需自行负责。
概念

子查询使用指导
- 子查询要用括号括起来
- 将子查询放在比较运算符的右边
- 对于单行子查询要使用单行运算符
- 对于多行子查询要使用多行运算符
多行子查询
- 子查询返回记录的条数 可以是一条或多条。
- 和多行子查询进行比较时,需要使用多行操作符,多行操作符包括:
- IN
- ANY
- ALL
- IN操作符和以前介绍的功能一致,判断是否与子查询 的任意一个返回值相同
ROWNUM
- ROWNUM是一个伪列,伪列是使用上类似于表中的列,而 实际并没有存储在表中的特殊列;
- ROWNUM的功能是在每次查询时,返回结果集的顺序号, 这个顺序号是在记录输出时才一步一步产生的,第一行 显示为1,第二行为2,以此类推。
ROWNUM使用的注意点:
- 1.如下SQL语句,SELECT * FROM EMP WHERE ROWNUM>2;查询 不到任何记录,因为ROWNUM是在记录输出时才生成,且总是 从1开始,所以输出的第一条记录不满足>2的条件,被过滤掉, 第二条的ROWNUM又成了1,又不满足〉2的条件,又被过滤掉, 依此类推,所以永远没有满足条件的记录,返回为空。所以 对于ROWNUM只能执行<、<=运算,不能执行>、>=或一个区间 运算Between..And等
- 2.ROWNUM和ORDER BY一起使用时,因为ROWNUM在记录输出时 生成,而ORDER BY子句在最后执行,所以当两者一起使用时, 需要注意ROWNUM实际是已经被排了序的ROWNUM。
TOP-N查询
- Top-N查询主要是实现表中按照某个列排序,输出最大或 最小的N条记录功能。
- Top-N分析语法:
SELECT [列名], ROWNUM
FROM (SELECT [列名]
FROM 表名
ORDER BY Top-N操作的列 ASC|DESC)
WHERE ROWNUM <= N;
ASC:查询最小的N条记录
DESC:查询最大的N条记录
分页查询
- 在Oracle中,利用ROWNUM的特性,可以实现数据库端的分 页查询,查询语法为:
- 1.当未指定需要按照某列排序,语法为:
- 在Oracle中,利用ROWNUM的特性,可以实现数据库端的分 页查询,查询语法为:
SELECT b.*
FROM (SELECT ROWNUM rn,[列名1,列名2,....列名n]
FROM 表名1,[表名2,...表名n]
WHERE [条件表达式 AND ] ROWNUM <=目标页数*每页记录数) b
WHERE rn > (目标页数-1)*每页记录数
或
SELECT b.*
FROM (SELECT ROWNUM rn,[列名1,列名2,....列名n]
FROM 表名1,[表名2,...表名n]
[WHERE 条件表达式]) b
WHERE rn <=目标页数*每页记录数 and rn > (目标页数-1)*每页记录数
思考:哪种方式效率高?
+ 2.当指定需要按照某列排序时,语法为:
SELECT *
FROM (SELECT ROWNUM rn, b.*
FROM (SELECT 列名1 [,列名2,....列名n]
FROM 表名1,[表名2,...表名n]
[WHERE 子句]
ORDER BY 要排序的列 ASC|DESC ) b
WHERE ROWNUM <=目标页数*每页记录数
)
WHERE rn > (目标页数-1)*每页记录数 ;
或:
SELECT *
FROM (SELECT ROWNUM rn, b.*
FROM (SELECT 列名1 [,列名2,....列名n]
FROM 表名1,[表名2,...表名n]
[WHERE 子句]
ORDER BY 要排序的列 ASC|DESC ) b
)
WHERE rn <=目标页数*每页记录数 and rn > (目标页数-1)*每页记录数;
示例代码
-----------------------------------------------
-- 使用子查询
-- ① 子查询(内部查询)优先执行
-- ② 将步骤①中查询的结果交给父查询(外部查询)使用,用于确认或取消数据
--
-- 单行子查询使用单行运算符:> >= = < <= <>
-- 多行子查询使用多行运算符:in any all
-----------------------------------------------
1.查询出比JONES雇员工资高的其他雇员
select sal from emp where ename = 'JONES'; --1. jones的工资是多少? 2975.00
select * from emp where sal > (select sal from emp where ename = 'JONES');--2.查询出比JONES雇员工资高的其他雇员
-----------------------------------------------------------
--单行子查询:返回一行一列 使用单行运算符:> >= = < <= <>
-----------------------------------------------------------
1.显示和雇员7369从事相同工作并且工资大于雇员7876的雇员的姓名和工作。
select job from emp where empno = 7369; --1.雇员7369从事的工作是什么 CLERK
select sal from emp where empno = 7876; --2.雇员7876的工资是多少 1100.00
select ename, job
from emp
where job = (select job from emp where empno = 7369)
and sal > (select sal from emp where empno = 7876); --3.主查询
--子查询中使用组函数
1.查询工资最低的员工姓名,岗位及工资
select min(sal) from emp; --1. 查询最低工资是多少 800
select * from emp where sal = (select min(sal) from emp);--2. 主查询
--HAVING子句中使用子查询
1.查询部门最低工资比20部门最低工资高的部门编号及最低工资
select min(sal) from emp where deptno = 20; --1. 20部门最低工资 800
select deptno,min(sal) from emp group by deptno having min(sal) > 800;--2. 主查询
2.查询哪个部门的员工人数高于各部门平均人数。
select avg(count(empno)) from emp group by deptno; --1. 各部门平均人数 3.5
select deptno, count(empno)
from emp
group by deptno
having count(empno) > (select avg(count(empno)) from emp group by deptno); --2. 主查询
--练习
4.查询部门人数大于所有部门平均人数的的部门编号,部门名称,部门人数
select avg(count(empno)) from emp group by deptno; --1.所有部门平均人数 3.5
select e.deptno, d.dname, count(empno)
from emp e, dept d
where e.deptno = d.deptno
group by e.deptno, d.dname
having count(empno) > (select avg(count(empno)) from emp group by deptno); --2.主查询
-----------------------------------------------------------
--多行子查询:返回多行一列 使用多行运算符:in any all
-----------------------------------------------------------
--in
1.查询员工工资为各个部门最低工资的员工信息
select min(sal) from emp group by deptno;-- null 950 800 1300
select empno, ename
from emp
where sal = (select min(sal) from emp group by deptno);-- not ok 单行子查询返回多个结果
select empno, ename,sal
from emp
where sal in (select min(sal) from emp group by deptno);--ok
2.查询是经理的员工姓名,工资
select distinct mgr from emp; --1.查询哪些人是经理? 7839,7782,7698,7902,7788,7566
select * from emp where empno in(select distinct mgr from emp);-- 2.主查询
--ANY 与任意值匹配 <any >any =any(相当于in)
-- =any(相当于in):与子查询的任意一个值相等
1.查询是经理的员工姓名,工资。
select distinct mgr from emp; --1.查询哪些人是经理? 7839,7782,7698,7902,7788,7566
select * from emp where empno =any (select distinct mgr from emp);-- 2.主查询
-- >any :大于最小值
2.查询部门编号不为10,且工资比10部门【任意】一名员工工资【高】的员工编号,姓名,职位,工资。
select sal from emp where deptno = 10; --1.查询10部门所有员工的工资 2450.00,5000.00,1300.00
select empno,ename,job,sal from emp where sal >any (select sal from emp where deptno = 10) and deptno <> 10;-- 2.主查询
-- <any :小于最大值
3.查询部门编号不为10,且工资比10部门【任意】一名员工工资【低】的员工编号,姓名,职位,工资。
select sal from emp where deptno = 10; --1.查询10部门所有员工的工资 2450.00,5000.00,1300.00
select empno,ename,job,sal from emp where sal <any (select sal from emp where deptno = 10) and deptno <> 10;-- 2.主查询
--ALL 与所有值匹配 <all >all =all(无意义)
-- =all :等于所有值
1.【无意义】查询部门编号不为10,且工资与10部门【所有】员工工资【相等】的员工编号,姓名,职位,工资。
select sal from emp where deptno = 10; --1.查询10部门所有员工的工资 2450.00,5000.00,1300.00
select empno,ename,job,sal from emp where sal =all (select sal from emp where deptno = 10) and deptno <> 10;-- 2.主查询
-- >all :大于最大值
2.查询部门编号不为10,且工资比10部门【所有】员工工资【高】的员工编号,姓名,职位,工资。
select sal from emp where deptno = 10; --1.查询10部门所有员工的工资 2450.00,5000.00,1300.00
select empno,ename,job,sal from emp where sal >all (select sal from emp where deptno = 10) and deptno <> 10;-- 2.主查询
-- <all :小于最小值
3.查询部门编号不为10,且工资比10部门【所有】员工工资【低】的员工编号,姓名,职位,工资。
select sal from emp where deptno = 10; --1.查询10部门所有员工的工资 2450.00,5000.00,1300.00
select empno,ename,job,sal from emp where sal <all (select sal from emp where deptno = 10) and deptno <> 10;-- 2.主查询
-----------------------------------------------------------
--多列子查询:返回多行多列 通常用多行运算符:in
-----------------------------------------------------------
--成对比较
1.查询出和1981年入职的【任意】一个员工的【部门和职位完全相同】员工姓名、部门、职位、入职日期,不包括1981年入职员工
select * from emp where hiredate between '1-1月-81' and '31-12月-81'; --1.1981年入职的员工的部门和职位
select * from emp where substr(hiredate,-2) = '81'; --1.1981年入职的员工的部门和职位
select * from emp where to_char(hiredate,'yyyy') = '1981'; --1.1981年入职的员工的部门和职位
select * from emp where extract(year from hiredate) = '1981'; --1.1981年入职的员工的部门和职位
select distinct deptno,job from emp where extract(year from hiredate) = '1981'; --1.1981年入职的员工的部门和职位
select *
from emp
where (deptno, job) = any (select distinct deptno,job from emp where extract(year from hiredate) = '1981')
and extract(year from hiredate) <> '1981'; --2.主查询
--不成对比较
1.查询出和1981年入职的【任意】一个员工的【部门或职位相同】员工姓名、部门、职位、入职日期,不包括1981年入职员工。
select distinct deptno from emp where extract(year from hiredate) = '1981'; --1.1981年入职的员工的部门
select distinct job from emp where extract(year from hiredate) = '1981'; --2.1981年入职的员工的职位
select *
from emp
where (deptno in (select distinct deptno from emp where extract(year from hiredate) = '1981')
or job in (select distinct job from emp where extract(year from hiredate) = '1981'))
and extract(year from hiredate) <> '1981';
--子查询中的null值
1.查询是经理的员工姓名,工资
select distinct mgr from emp; --1.查询哪些人是经理? null,7839,7782,7698,7902,7788,7566
select * from emp where empno in(select distinct mgr from emp); -- 2.主查询
2.查询不是经理的员工姓名
select distinct mgr from emp where mgr is not null; --1.查询哪些人是经理? 7839,7782,7698,7902,7788,7566
select * from emp where empno not in(select distinct mgr from emp where mgr is not null);--2.主查询
--在from子句中使用子查询
1.查询比自己部门平均工资高的员工姓名,工资,部门编号,部门平均工资
select deptno,avg(sal) from emp group by deptno;--1.部门平均工资
select e.ename,e.sal,e.deptno,s.avgsal from emp e,(select deptno,avg(sal) avgsal from emp group by deptno) s where e.deptno = s.deptno and e.sal > s.avgsal;
--练习
1.查询比自己职位平均工资高的员工姓名、职位,部门名称,职位平均工资
select job,avg(sal) avgsal from emp group by job;--1.职位平均工资
select e.ename,e.job,d.dname,s.avgsal
from emp e, dept d, (select job, avg(sal) avgsal from emp group by job) s
where e.deptno = d.deptno
and e.job = s.job
and e.sal > s.avgsal;
--rownum:伪列,永远从1开始
-- 注意: rownum只能执行<、<=运算,不能执行>、>=或一个区间运算Between..And等
--TOP-N查询
1.查询工资最高的三个员工的信息
select rownum,e1.* from (select emp.* from emp where sal is not null order by sal desc) e1 where rownum <= 3;
2.查询工资最低的三个员工的信息
select rownum,e1.* from (select emp.* from emp where sal is not null order by sal) e1 where rownum <= 3;
--数据库分页
假设每页显示5条
1 1-5
2 6-10
3 11-15
4 16-20
开始下标:每页显示条数 * 当前页码-(每页显示条数-1)= 每页显示条数*当前页码-每页显示条数+1=(当前页码-1)*每页显示条数 + 1
结束下标:每页显示条数 * 当前页码
1.查询第一页数据
select rownum,e.* from emp e where rownum <= 5;
2.查询第二页数据
select e1.* from (select rownum rn,e.* from emp e where rownum <= 10) e1 where e1.rn >= 6; --效率高,仅查询10条
select e1.* from (select rownum rn,e.* from emp e) e1 where e1.rn <= 10 and e1.rn >= 6; --效率低,永远查询所有数据
3.查询第三页数据
select e1.* from (select rownum rn,e.* from emp e where rownum <= 15) e1 where e1.rn >= 11;
select e1.* from (select rownum rn,e.* from emp e) e1 where e1.rn <= 15 and e1.rn >= 11;
--公用的SQL分页查询语句
select e1.* from (select rownum rn,e.* from emp e where rownum <= &end) e1 where e1.rn >= &begin;
select e1.* from (select rownum rn,e.* from emp e where rownum <= (每页显示条数 * 当前页码)) e1 where e1.rn >= (当前页码-1)*每页显示条数 + 1);
select e1.* from (select rownum rn,e.* from emp e) e1 where e1.rn <=(每页显示条数 * 当前页码) and e1.rn >= (当前页码-1)*每页显示条数 + 1);
--数据分页前,先排序
1.根据入职日期降序排序后,再分页
select *
from (select rownum rn, e1.*
from (select emp.* from emp order by hiredate desc) e1
where rownum <= 10) e2
where e2.rn >= 6;
--练习
1.按照每页显示5条记录,分别查询工资最高的第1页,第2页,第3页信息,要求显示员工姓名、入职日期、部门名称、工资。
select *
from (select rownum rn, e2.*
from (select * from emp order by sal desc) e2,dept d
where e2.deptno = d.deptno and rownum <= 10) e3
where rn >= 6;
select *
from (select rownum rn, e2.*
from (select * from emp order by sal desc) e2
where rownum <= 10) e3,
dept d
where e3.deptno = d.deptno
and rn >= 6;
select *
from (select rownum rn, e2.*
from (select e.*, d.dname,d.loc
from emp e, dept d
where e.deptno = d.deptno
order by sal desc) e2
where rownum <= 10) e3
where rn >= 6;
--练习
14. 列出至少有一个雇员的所有部门
--分组语句
select deptno,count(empno) from emp group by deptno having count(empno) >= 1;--分组语句
--嵌套子查询
select deptno,count(empno) from emp group by deptno;--1.查询部门人数
select * from (select deptno,count(empno) ecount from emp group by deptno) d where d.ecount >= 1;--2.主查询
select deptno,count(empno) from emp group by deptno;--1.查询部门人数
select * from dept d,(select deptno,count(empno) ecount from emp group by deptno) c where d.deptno = c.deptno(+) and c.ecount >=1;--2.主查询
--相关子查询
select * from dept where exists (select * from emp where deptno= dept.deptno);--1.相关子查询
24. 显示每位经理管理员工的最低工资,及最低工资者的姓名
select mgr,min(sal) from emp group by mgr;--1.每位经理管理员工的最低工资
select * from emp e,(select mgr,min(sal) minsal from emp group by mgr) s where e.mgr = s.mgr and e.sal = s.minsal;--2.主查询
25. 显示比工资最高的员工参加工作时间晚的员工姓名,参加工作时间
select max(sal) from emp; --1.最高的工资 5000
select hiredate from emp where sal = (select max(sal) from emp);--2.查工资最高的员工的参加工作的时间 1981/11/17
select * from emp where hiredate > (select hiredate from emp where sal = (select max(sal) from emp));--3.主查询
26. 显示出平均工资最高的的部门平均工资及部门名称
select deptno,avg(sal) from emp group by deptno; --1.部门平均工资
select max(avg(sal)) from emp group by deptno; --1.部门的最高平均工资---补充 2916.66666666667
select e.deptno, d.dname, avg(e.sal) avgsal
from emp e, dept d
where e.deptno = d.deptno
group by e.deptno, d.dname
having avg(e.sal) = (select max(avg(sal)) from emp group by deptno); --2.主查询
--借助rownum实现
select *
from (select e.deptno, d.dname, avg(e.sal) avgsal
from emp e, dept d
where e.deptno = d.deptno
group by e.deptno, d.dname
order by avgsal desc) e
where rownum = 1;
分割线
相关信息
以上就是我关于 Oracle-SQL开发 —— 子查询 知识点的整理与总结的全部内容,希望对你有帮助。。。。。。。
Powered by Waline v2.15.4