目录
=========================================
1.窗口函数简介
2.窗口函数示例-全统计
3.窗口函数进阶-滚动统计(累积/均值)
4.窗口函数进阶-根据时间范围统计
5.窗口函数进阶-first_value/last_value
6.窗口函数进阶-比较相邻记录

一、窗口函数简介:

到目前为止,我们所学习的分析函数在计算/统计一段时间内的数据时特别有用,但是假如计算/统计需要随着遍历记录集的每一条记录而进行呢?举些例子来说:

①列出每月的订单总额以及全年的订单总额
②列出每月的订单总额以及截至到当前月的订单总额
③列出上个月、当月、下一月的订单总额以及全年的订单总额
④列出每天的营业额及一周来的总营业额
⑤列出每天的营业额及一周来每天的平均营业额

仔细回顾一下前面我们介绍到的分析函数,我们会发现这些需求和前面有一些不同:前面我们介绍的分析函数用于计算/统计一个明确的阶段/记录集,而这里有部分需求例如2,需要随着遍历记录集的每一条记录的同时进行统计。

也即是说:统计不止发生一次,而是发生多次。统计不至发生在记录集形成后,而是发生在记录集形成的过程中。

这就是我们这次要介绍的窗口函数的应用了。它适用于以下几个场合:

①通过指定一批记录:例如从当前记录开始直至某个部分的最后一条记录结束
②通过指定一个时间间隔:例如在交易日之前的前30天
③通过指定一个范围值:例如所有占到当前交易量总额5%的记录

二、窗口函数示例-全统计:

下面我们以需求:列出每月的订单总额以及全年的订单总额为例,来看看窗口函数的应用。

【1】测试环境:

SQL >   desc  orders;
 名称                    是否为空? 类型
  -- --------------------- -------- ---------------- 
  MONTH                              NUMBER ( 2 )
 TOT_SALES                     NUMBER

SQL >

【2】测试数据:

SQL >   select   *   from  orders;

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

已选择12行。

【3】测试语句:

回忆一下前面《Oracle开发专题之:分析函数(OVER) 》一文中,我们使用了sum(sum(tot_sales)) over (partition by region_id) 来统计每个分区的订单总额。现在我们要统计的不单是每个分区,而是所有分区,partition by region_id在这里不起作用了。

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行。

现在我们能得到滚动的销售总额了!下面这个统计结果看起来更加完美,它展现了所有我们需要的数据:

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           sum ( sum (tot_sales))  over ( order   by   month 
   6          rows  between  unbounded preceding  and  unbounded following ) total_sales
   7      from  orders
   8     group   by   month ;

MONTH  MONTH_SALES CURRENT_TOTAL_SALES TOTAL_SALES
-- -------- ----------- ------------------- ----------- 
          1        610697                610697       6307766 
          2        428676               1039373       6307766 
          3        637031               1676404       6307766 
          4        541146               2217550       6307766 
          5        592935               2810485       6307766 
          6        501485               3311970       6307766 
          7        606914               3918884       6307766 
          8        460520               4379404       6307766 
          9        392898               4772302       6307766 
         10        510117               5282419       6307766 
         11        532889               5815308       6307766 
         12        492458               6307766       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 天范围内的记录,并统计其销售平均值。

五、窗口函数进阶- first_value/last_value : 

Oracle 提供了 2 个额外的函数: first_value 、 last_value ,用于在窗口记录集中查找第一条记录和最后一条记录。假设我们的报表需要显示当前月、上一个月、后一个月的销售情况,以及每 3

个月的销售平均值,这两个函数就可以派上用场了。

select   month ,
             first_value ( sum (tot_sales))  over  ( order   by   month  
                                    rows  between   1  preceding  and   1  following) prev_month,
 
              sum (tot_sales) monthly_sales,
 
             last_value ( sum (tot_sales))  over  ( order   by   month  
                                  rows  between   1  preceding  and   1  following) next_month,
 
              avg ( sum (tot_sales))  over  ( order   by   month  
                                 rows  between   1  preceding  and   1  following ) rolling_avg
     from  orders
  where   year   =   2001  
       and  region_id  =   6 
   group   by   month 
  order   by   month ;

首先我们来看 :rows between 1 preceding and 1 following 告诉 Oracle 在当前记录的前一条、后一条范围内查找并统计,而 first_value 和 last_value 在这 3 条记录中至分别找出第一条、第三条记录,这样我们就轻松地得到相邻三个月的销售记录及平均值了!

六、窗口函数进阶-比较相邻 记录: 

通过第五部分的学习,我们知道了如何利用窗口函数来显示相邻的记录,现在假如我们想每次显示当月的销售额和上个月的销售额,应该怎么做呢?

从第五部分的介绍我们可以知道,利用 first_value(sum(tot_sales) over (order by month rows between 1 preceding and 0 following)) 就可以做到了,其实 Oracle 还有一个更简单的方式让我们来比较 2 条记录,它就是 lag函数。

leg 函数类似于 preceding 和 following

子句,它能够通过和当前记录的相对位置而被应用,在比较同一个相邻的记录集内两条相邻记录的时候特别有用。

select   month ,            
           sum (tot_sales) monthly_sales,
          lag( sum (tot_sales),  1 )  over  ( order   by   month )  prev_month_sales
    from  orders
  where   year   =   2001 
       and  region_id  =   6 
   group   by   month 
  order   by   month ;
 

lag(sum(tot_sales),1) 中的 1 表示以 1 月为基准。

本文转载自http://blog.csdn.net/cnham/article/details/6101199

Oracle开发之窗口函数 rows between unbounded preceding and current row的更多相关文章

  1. Oracle分析函数、窗口函数简单记录汇总

    一.分析函数.窗口函数一般形式 1.分析函数的形式分析函数带有一个开窗函数over(),包含三个分析子句:分组(partition by), 排序(order by), 窗口(rows) ,他们的使用 ...

  2. Oracle SQL Developer,Oracle 开发工具之toad、SQL Developer、PL/SQL Developer等比较

    参考: oracle 的几个开发工具比较 因Oracle几乎是中大型商业企业数据的首选,所以比较一下常用与Oracle的工具. Oracle SQL Developer 免费,一般开发使用足矣,常用. ...

  3. OTL之Oracle开发总结《转》

    OTL之Oracle开发总结---转   关 于OTL,网上介绍的也不少,但看来看去也只是官方的那些文档.OTL很好用,结合官方提供的一些例子,多多尝试才能领悟.经过一个月左右的项目开发,对 OTL也 ...

  4. SQL server 与Oracle开发比较

    ●概念上区别 1.Oracle 是一种对象关系数据库管理系统(ORDBMS),而Sql server 只是关系型数据库管 理系统(RDBMS). 2.Oracle使用Internet文件系统,该系统基 ...

  5. Oracle开发常用函数与存储过程

    create or replace function Fuc_Get_AuthorName(RecID_In in varchar2, AdmID_In in varchar2) return var ...

  6. Oracle开发包被锁解决办法-终极办法

    http://www.itpub.net/forum.php?mod=viewthread&tid=1761963 以前在数据库维护中,基本都是碰到表被锁的情况,然后就是查找被锁的表相关的信息 ...

  7. 慕课网笔记之oracle开发利器-PL/SQL基础

    实例1--if语句 /* 慕课网Oracle数据库开发必备之PL/SQL_2-3 判断用户从键盘输入的数字 1.如何使用if语句 2.接收一个键盘的输入(字符串) */ set serveroutpu ...

  8. Oracle开发 之 主-外键约束FK及约束的修改

    试验环境: 1)数据库版本:oracle 11.2.0.4 2)建表脚本:以scott的dept及emp表为基础. 父表:dept -- Create table create table DEPT ...

  9. oracle开发so easy(一)

    如何让你的程序可以在oracle数据库和sqlserver数据库自由切换? 如何让你从跨数据库开发的不适中解脱出来? 跟我来吧,我们一起开始entity framework的开发之旅.是的,entit ...

随机推荐

  1. C#中事件的使用

    C#中事件的使用  http://www.cnblogs.com/wayfarer/archive/2004/04/20/6712.html 用一个例子来说明事件的使用. 创建一个简单的类,名为Fil ...

  2. I got a plan in 2014

    工作快3年了,始终逃脱不出一种混日子打酱油的赶脚,一切都似乎是在虚度. 最近好像有患上很严重的拖延症,工作上总是分散精力,无法聚集自己的事情. 开始这个博客,希望记录一些有用文字,不管是工作.生活,还 ...

  3. xss漏洞挖掘小结

    xss漏洞挖掘小结 最近,在挖掘xss的漏洞,感觉xss真的不是想象的那样简单,难怪会成为一类漏洞,我们从防的角度来讲讲xss漏洞的挖掘方法: 1.过滤 一般服务器端都是采用这种方式来防御xss攻击, ...

  4. html、css杂记

    1:浮动 <div style="float: left"> 2:清除浮动,把父div撑起来 <div style="clear:both"& ...

  5. 利用ant脚本 自动构建svn增量/全量 系统程序升级包

    首先请允许我这样说,作为开发或测试,你一定要具备这种 本领.你可以手动打包.部署你的工程,但这不是最好的方法.最好的方式就是全自动化的方式.开发人员提交了代码后,可以自动构建.打包.部署到测试环境. ...

  6. 网页JQ基础之jq-隐藏以及显示特效

    简单的 隐藏以及显示的 JQ 的代码如下: <!DOCTYPE html> <html> <head> <script src="/jquery/j ...

  7. jQuery.validator 验证规则详解

    前言:jQuery.validator是一款非常不错的表单验证插件,验证方式非常简单方便,它还对HTML5做了兼容处理,了解了验证规则,就基本掌握了它的使用,下面就让我一一道来 jQuery.vali ...

  8. Android手机同步电脑端google chrome书签

    我先声明:文中FQ 都是博客园自动将中文(fan qiang)转换为FQ的,并不是我本来写的就是FQ~~ 手机和电脑都必须要能登录google(Xee:几乎所有做开发的人都每天的生活都离不开谷歌了,可 ...

  9. [译]Mongoose指南 - 中间件

    中间件是一些函数, 当document发生init, validate, save和remove方法的时候中间件发生. 中间件都是document级别的不是model级别的. 下面讲讲两种中间件pre ...

  10. tcp/ip协议栈调用关系图

    最近阅读了tcp/ip详解卷2,总结一下整个发送过程和接收过程 sendmsg \/ sendit \/ sosend(这一步将数据从用户空间拷贝到内核空间,并且会在这一步判断发送缓存空间是否充足,是 ...