由于工作中经常需要写相对复杂的SQL,在龙哥的指导下,学习了下oracle的分析函数,觉得功能很强大,记录下来,当作学习,先在此谢谢龙哥了。
一.首先先来了解下什么是Oracle的分析函数吧
顾名思义,在查询结果的基础上进行分析,也就是说,以一定的方法在一个与当前行相关的结果集子集进行计算。
二.分析函数的列表
三.准备工作
- 表结构和数据
create table SC ( sno VARCHAR2(10) not null, cno VARCHAR2(10) not null, score NUMBER(4,2) ) insert into sc (SNO, CNO, SCORE) values ('s001', 'c001', 78.90); insert into sc (SNO, CNO, SCORE) values ('s002', 'c001', 80.90); insert into sc (SNO, CNO, SCORE) values ('s003', 'c001', 81.90); insert into sc (SNO, CNO, SCORE) values ('s004', 'c001', 60.90); insert into sc (SNO, CNO, SCORE) values ('s001', 'c002', 82.90); insert into sc (SNO, CNO, SCORE) values ('s002', 'c002', 72.90); insert into sc (SNO, CNO, SCORE) values ('s003', 'c002', 81.90); insert into sc (SNO, CNO, SCORE) values ('s001', 'c003', 59.00);
- 基本语法
row_number() over (partition by bill_code order by scan_date desc) as r_num; --这段代码主要是以单号进行分区,按时间进行降序。 --现在来分析下这段代码: --1.row_number() 就是一个函数名 --2.over是一个关键字,用于标识分析函数,不然查询分析器不能区分是聚集函数还是分析函数 --3.partition by 是可选分区子句,如果不存在任何分区子句,那么将全部的结果集看作是一个单一的大区 --4.order by 是可选的order by子句,它指定了计算分析函数时一组内的数据是如何排序的。
3.数据
四.挑选几个比较常用的函数来分析下吧
Lag
/*语法: lag(exp_str,offset,defval) over() exp_str要取的列 offset取偏移前的第几行数据 defval:没有符合条件的默认值*/ --执行语法 select t.sno,t.cno,t.score,lag(score, 1, 0) over(order by t.score desc) as preScore from sc t
由图片我们可以看出 lag(score,1,0) over(order by t.score desc),以score进行降序,lag(score,1,0),1代表取上一行score的值,
如果上一行没有值得话则会为0,由第一条数据可知
Lead
/*语法: lead(exp_str,offset,defval) over() exp_str要取的列 offset取偏移后的第几行数据 defval:没有符合条件的默认值*/ --执行语法 select t.sno,t.cno,t.score,lead(score, 1, 0) over(order by t.score desc) as preScore from sc t
可参考Lag备注 --以学号进行分组,然后看下结果集 select t.sno,t.cno,t.score,lead(score, 1, 0) over(partition by sno order by t.score desc) as preScore from sc
来分析下上面这条SQL,首先先以学号进行一个分组,然后按成绩降序,取下一行的SCORE列,可参考结果集很容易看出区别的
row_number()over
--这个分析函数用得比较多,所以重点讲解下下面的函数
--row_number()over 对行进行排序并为每一行增加一个唯一的编号
--假如我们现在有这样的一个需求,取出成绩表中成绩最低的课程号和对应的学生 --如果不使用分析函数 select t.sno,t.cno,t.score from sc t where t.score=( select min(score) from sc where cno='c001' group by cno ) --下面是使用分析函数 select t1.sno, t1.cno, t1.score from (select t.sno,t.cno,t.score, row_number() over(order by score asc) as r_num from sc t where t.cno = 'c001') t1 where t1.r_num = 1 /*虽然这样看不出有这么区别,但假如客户的需求变了,想实现这样,查看当前成绩表中 每们课程最低成绩对应的是哪一位学生的话,传统语法可能写起来相麻烦点,但分析函数写起来就简单粗暴多了。*/ select t1.sno, t1.cno, t1.score from (select t.sno,t.cno,t.score, row_number() over(partition by cno order by score asc) as r_num from sc t) t1 where t1.r_num = 1
将CNO进行一个分区,以成绩进行升序。子查询先执行,这样我们可以得到一个r_num的列,如下图所示
由上图我们可知,C001,C002,C003各自为一个分区,以成绩升序排序,这样我们可以看到,
R_NUM 由小到大依次升序,这样我们就可以在外层取出最低的成绩了。
sum()over()
--1.sum()over()简单点的说就是将某个连续字段进行求和 select t.sno,t.cno,t.score, sum(score)over() as sum_num from sc t
可以看下sum_num ,这段代码的作用就是将 score这个字段进行一个求和,得到一个集,显示出来而已
--2. sum()over(order by score asc)根据分组的score进行升序求和 select t.sno,t.cno,t.score, sum(score)over(order by score asc) as sum_num from sc t
sum(score)over(order by score asc) as sum_num 这段代码其实我也不知道怎么说,
第n行的SUM_NUM+第n行的SCORE=n+1行的SUM_NUM
--3. sum(score)over(partition by cno order by score asc) 以cno 进行分区, --然后按成绩升序进行求和 select t.sno,t.cno,t.score, sum(score)over(partition by cno order by score asc) as sum_num from sc t
五.总结
其实分析函数的用法大同小异,我就不一一列举了,只能说我太懒,哈哈!不对的地方请各位大神多多指教!