oracle 分析函数

      由于工作中经常需要写相对复杂的SQL,在龙哥的指导下,学习了下oracle的分析函数,觉得功能很强大,记录下来,当作学习,先在此谢谢龙哥了。

     一.首先先来了解下什么是Oracle的分析函数吧

   顾名思义,在查询结果的基础上进行分析,也就是说,以一定的方法在一个与当前行相关的结果集子集进行计算。

  

      二.分析函数的列表

      

  三.准备工作 

  1. 表结构和数据
    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);
    View Code
  2.  基本语法
    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子句,它指定了计算分析函数时一组内的数据是如何排序的。
    View Code

      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

  

  

  五.总结

     其实分析函数的用法大同小异,我就不一一列举了,只能说我太懒,哈哈!不对的地方请各位大神多多指教!

原文地址:https://www.cnblogs.com/SmallHan/p/6741163.html