oracle分析函数系列之sum() rows/range between ... preceding and ... following,上下范围内求值

Oracle为这种情况提供了一个子句:rows between ... preceding and ... following。从字面上猜测它的意思是:在XXX之前和XXX之后的所有记录,实际情况如何让我们通过示例来验证:

SQL> select month,
  
2         sum(tot_sales) month_sales,
  
3         sum(sum(tot_sales)) over (order by month
  
4            rows between unbounded preceding and unbounded following) total_sales
  
5    from orders
  
6   group by month;

     
MONTH MONTH_SALES TOTAL_SALES
---------- ----------- -----------
         1      610697     6307766
         
2      428676     6307766
         
3      637031     6307766
         
4      541146     6307766
         
5      592935     6307766
         
6      501485     6307766
         
7      606914     6307766
         
8      460520     6307766
         
9      392898     6307766
        
10      510117     6307766
        
11      532889     6307766
        
12      492458     6307766

已选择12行。


绿色高亮处的代码在这里发挥了关键作用,它告诉oracle统计从第一条记录开始至最后一条记录的每月销售额。这个统计在记录集形成的过程中执行了12次,这时相当费时的!但至少我们解决了问题。

unbounded preceding and unbouned following的意思针对当前所有记录的前一条、后一条记录,也就是表中的所有记录。那么假如我们直接指定从第一条记录开始直至末尾呢?看看下面的结果:

SQL> select month,
  
2         sum(tot_sales) month_sales,
  
3         sum(sum(tot_sales)) over (order by month
  
4            rows between 1 preceding and unbounded following) all_sales
  
5    from orders
  
6   group by month;

     
MONTH MONTH_SALES  ALL_SALES
---------- ----------- ----------
         1      610697    6307766
         
2      428676    6307766
         
3      637031    5697069
         
4      541146    5268393
         
5      592935    4631362
         
6      501485    4090216
         
7      606914    3497281
         
8      460520    2995796
         
9      392898    2388882
        
10      510117    1928362
        
11      532889    1535464
        
12      492458    1025347

已选择12行。


很明显这个语句错了。实际1在这里不是从第1条记录开始的意思,而是指当前记录的前一条记录。preceding前面的修饰符是告诉窗口函数执行时参考的记录数,如同unbounded就是告诉oracle不管当前记录是第几条,只要前面有多少条记录,都列入统计的范围。

 

窗口函数进阶-滚动统计(累积/均值):

考虑前面提到的第2个需求:列出每月的订单总额以及截至到当前月的订单总额。也就是说2月份的记录要显示当月的订单总额和1,2月份订单总额的和。3月份要显示当月的订单总额和1,2,3月份订单总额的和,依此类推。

很明显这个需求需要在统计第N月的订单总额时,还要再统计这N个月来的订单总额之和。想想上面的语句,假如我们能够把and unbounded following换成代表当前月份的逻辑多好啊!很幸运的是Oracle考虑到了我们这个需求,为此我们只需要将语句稍微改成: curreent row就可以了。

SQL> select month,
  
2         sum(tot_sales) month_sales,
  
3         sum(sum(tot_sales)) over(order by month
  
4           rows between unbounded preceding and current row) current_total_sales
  
5    from orders
  
6   group by month;

     
MONTH MONTH_SALES CURRENT_TOTAL_SALES
---------- ----------- -------------------
         1      610697              610697
         
2      428676             1039373
         
3      637031             1676404
         
4      541146             2217550
         
5      592935             2810485
         
6      501485             3311970
         
7      606914             3918884
         
8      460520             4379404
         
9      392898             4772302
        
10      510117             5282419
        
11      532889             5815308
        
12      492458             6307766

已选择12行。

在一些销售报表中我们会时常看到求平均值的需求,有时可能是针对全年的数据求平均值,有时会是针对截至到当前的所有数据求平均值。很简单,只需要将:
sum(sum(tot_sales))换成avg(sum(tot_sales))即可。

 

窗口函数进阶-根据时间范围统计:

前面我们说过,窗口函数不单适用于指定记录集进行统计,而且也能适用于指定范围进行统计的情况,例如下面这个SQL语句就统计了当天销售额和五天内的评价销售额:

 select trunc(order_dt) day,
             sum(sale_price) daily_sales,
             avg(sum(sale_price)) over (order by trunc(order_dt)
                      range between interval '2' day preceding 
                                     and interval '2' day following) five_day_avg
   from cust_order
 where sale_price is not null 
     and order_dt between to_date('01-jul-2001','dd-mon-yyyy')
     and to_date('31-jul-2001','dd-mon-yyyy')

为了对指定范围进行统计,Oracle使用关键字range、interval来指定一个范围。上面的例子告诉Oracle查找当前日期的前2天,后2天范围内的记录,并统计其销售平均值。



  • 5
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值