Oracle中子查询、分页查询、排序函数通俗理解

时间:2024-03-22 16:39:45

一、子查询
1、子查询在where子句中
(1)实例: 查找和SCOTT同职位的员工
思路分析:
1.和xx怎么样,与xx怎么样,比xx怎么样,大于,小于,等于,是,不是,为,等大范围过滤的条件:肯定要用到where
2.和SCOTT同职位 要用到where,SCOTT同职位?我们到现在还不知道SCOTT是啥子情况,先把SCOTT的情况查询出来,这就是子查询。
3.重点是后面的员工,我们最终要查询的是员工,而不是SCOTT同职位,所以是个主查询。
4.其实where条件过滤后面跟的就是实实在在的东西,
(1)如where sal > 100 100是实在存在的东西
(2)如 where job = SCOTT同职位, 因为我们需要知道SCOTT同职位 是实在存在的东西,但是我们现在真的不知道它是个啥,也就是说它不实在,那么就得查询出来,它是个啥,把它变成实在的东西。
select job from emp where ename = ‘SCOTT’;
5.因此,where前面的select查询里的东西是要上台面的,是主查询,跟在where后面的条件的东西必须是个实在的东西,如果不是,那就把它查询出来变成实在的东西,所以where后面需要通过查询变成实在的东西就是个子查询。
6. 主查询和子查询之间用 where job = 这样的语句连起来。

(2)SQL查询语句:
1.where后面的子查询
select job from emp where ename = ‘SCOTT’;
2.主查询 select
select ename,job from emp;
3.主查询和子查询结合
select ename,job from emp where job = (select job from emp where ename = ‘SCOTT’);
查询结果:
Oracle中子查询、分页查询、排序函数通俗理解
其实,3.中的SQL语句已经能够成功查询出结果了。但是请看下面第4.说明。

4.子查询就是个where过滤条件,已经固定。主查询中出现了job,子查询中也有job,二者要区分开来,不然
谁知道你这个job是主查询里要查询的job还是子查询中的job。
总结起来:子查询固定,主查询防止混淆,进行改善。
这样看起来,SQL语句结构更合理,舒适。e就相当于emp的一个实例一样,以后建议使用4,尽管3也是对的。

select e.ename,e.job from emp e where e.job = (select job from emp where ename = ‘SCOTT’);
查询结果:
Oracle中子查询、分页查询、排序函数通俗理解
(3)多子查询
查询出部门中有SALESMAN但职位不是SALESMAN的员工的信息:
子查询:select deptno from emp where job = ‘SALESMAN’;
子查询:job <> ‘SLAESMAN’;
主查询:select empno,ename,job,sal,deptno from emp;
主查询+子查询
select empno,ename,job,sal,deptno from emp where deptno in (select deptno from
emp where job = ‘SALESMAN’) and job <> ‘SALESMAN’;
Oracle中子查询、分页查询、排序函数通俗理解
主查询加上多子查询,无非是在where后面把多个子查询语句合理的连在一起,这里就用了 and 操作符。

2、子查询在having子句中
(1)实例:列出有员工的部门信息
主查询:select deptno,dname from dept;
子查询:select * from emp e where e.deptno = d.deptno;
主查询和子查询结合:
select d.deptno,d.dname from dept d where exists (select * from emp e where e.deptno = d.deptno);
查询结果:正好验证了部门40没有员工存在。
Oracle中子查询、分页查询、排序函数通俗理解
(2)实例:查询列出最低薪水高于部门30的最低薪水的部门信息
思路分析:按部门分,存在group by 而且having往往跟在 group by 后面
主查询:select deptno,min(sal) min_sal from emp group by deptno;
子查询:select min(sal) as min_sal from emp where deptno = 30;
结合起来:select deptno,min(sal) min_sal from emp group by deptno having min(sal) > (select min(sal) as min_sal from emp where deptno = 30);
查询结果:
Oracle中子查询、分页查询、排序函数通俗理解
(3)小结:通过上面(2)中子查询在having子句中,可以发现:
1.主查询和子查询都是select 的查询语句
2.根据需求,很明显末尾的东西是由主查询组成,中间的东西由子查询和连接子句组成。
就拿本例来说,查询列出最低薪水高于部门30的最低薪水的部门信息。
主查询:select 部门信息
子查询:select 部门30的最低薪水
连接子句:最低薪水高于
3.关键在于确定连接子句使用什么
最低薪水高于,有高于二字,可以使用where ,having,其中where是属于大过滤条件,而having是属于小过滤条件。
而我们由需求可以得出是按部门分组的,那么就有 group by,而按部门分组了后,信息量就少很多了,可以考虑使用小过滤条件,而且 having 往往跟在 group by 的后面的。
所以,最终,连接子句为 having min(sal) >
4. 要注意的是在连接子句为 having min(sal) >,不要写成了min_sal 或 min(sal) as min_sal,毕竟只有在select后面要上台面的东西才能写成min(sal) as min_sal
5.最后的SQL查询语句为 主查询 + 连接子句 + 子查询。多个子查询,就加个 and 连起来。

(4)实例:查询出薪水比本部门平均薪水高的员工信息。
主查询:select deptno,ename,sal from emp;
子查询:select deptno,avg(sal) as avg_sal from emp group by deptno;
1.select deptno,ename,sal,avg(sal) as avg_sal from emp where sal > avg(sal) group by deptno;
上面这条语句错误,不能使用分组函数,因为有sal,ename造成deptno重复
2.改正
select e.deptno,e.ename,e.sal from emp e join (select deptno,avg(sal) as
avg_sal from emp group by deptno) d on e.deptno = d.deptno where
e.sal > d.avg_sal order by e.deptno;
2.查询结果:
Oracle中子查询、分页查询、排序函数通俗理解
3.按教材里的答案:
select e.deptno,e.ename,e.sal from emp e,(select deptno,avg(sal) as avg_sal from emp group by deptno) d where e.deptno = d.deptno and e.sal > d.avg_sal order by e.deptno;
3. 查询结果:
Oracle中子查询、分页查询、排序函数通俗理解
很显然,2.和3.的查询结果一致。这里就把主查询和子查询当成两个表,进行连接。感觉2.比3.好。

二、分页查询
1、实例:
1. select rownum,empno,ename,sal from emp;
Oracle中子查询、分页查询、排序函数通俗理解
2. select rownum,empno,ename,sal from emp where rownum = 1;
Oracle中子查询、分页查询、排序函数通俗理解
3.select * from (select rownum m,e.* from emp e);
Oracle中子查询、分页查询、排序函数通俗理解
4. select * from (select rownum m,e.* from emp e) where m between 8 and 10;
Oracle中子查询、分页查询、排序函数通俗理解

2、实例:
select * from (select rownum m,t.*from(select empno,ename,sal from emp order by sal desc) t) where m between 8 and 10;
Oracle中子查询、分页查询、排序函数通俗理解
3、分页查询小结: rownum
1. 要查询字段原始表 —表1
2.查询(rownum字段 + 表1) —表2
3. 查询表2,进行分页条件
即:三查加分页
内表,查询需求 select empno,ename… from
中表,查询rownum 和需求形成的表 select rownum m,t.* from
外表,查询总表 select * from

三、排序函数
1、说明
格式:都是 XX() over (partition by col1 order by col2)
这一个整体跟min(sal)是一个性质的
表示根据col1分组,在分组内部根据col2给予等级标识,等级标识即排名

3个排序函数都是这样的格式,只是等级标识的排名不同而已。
row_number()
rank()
dense_rank()

2、排序函数实例
1.row_number
select deptno,ename,empno,row_number() over (partition by deptno order by empno) as emp_id from emp;
查询结果:
Oracle中子查询、分页查询、排序函数通俗理解
坦白讲,因为查询的是deptno,ename,empno,所以不可能有相同数据,因此rownum肯定是在分组后,按顺序从1开始排序

(1) 现在测试一下,将ename,empno拿掉,换成查询job,col2按job排名,重新查询,这次来看看遇到有相同数据rownum是怎么排序的。
select deptno,job,row_number() over (partition by deptno order by job) as emp_id from emp;
查询结果:
Oracle中子查询、分页查询、排序函数通俗理解
我们可以看到,有相同的数据:如 20 ANALYST 20 CLERK 30 SALESMAN
即使有重复相同数据,还是顺序排序的。

  1. rank()
    为测试等级标识的排名,这里就不查询ename,empno,换成查询job,排名也按job来
    select deptno,job,rank() over (partition by deptno order by job) as rank_id from emp;
    查询结果:
    Oracle中子查询、分页查询、排序函数通俗理解
    很明显:跳跃排序 1 1 3 3 5

  2. dense_rank
    为测试等级标识的排名,这里就不查询ename,empno,换成查询job,排名也按job来
    select deptno,job,dense_rank() over (partition by deptno order by job) as rank_id from emp;
    查询结果:
    Oracle中子查询、分页查询、排序函数通俗理解
    很明显:1 1 2 2 3

3、总结
其实可以把类似 dense_rank() over (partition by deptno order by job) as rank_id 这样的看成一个与 min(sal) as min_sal一样的字段,只不过,dense_rank() over (partition by deptno order by job) as rank_id 这个特殊的字段有自己特殊的功能罢了,它可以按deptno分组,按job排序。

也就是说:select deptno,job,dense_rank() over (partition by deptno order by job) as rank_id from emp;
字段 deptno 是查询部门编号
字段 job是查询工作职位
字段 dense_rank() over (partition by deptno order by job) as rank_id 是查询”按部门分组,按工作职位排名“

4、排序函数的clo2排名比较
当下列三个排序函数:进行排序,有并列第二的情况,那么下一列的排序的标记是:
row_number不管有没有重复值,始终顺序往下标记下去: 1 2 3 4
rank有重复值,是跳跃排序 : 1 2 2 4
dense_rank有重复值时: 1 2 2 3