oracle窗口函数的使用

来源:互联网 发布:海淘公司 知乎 编辑:程序博客网 时间:2024/05/13 01:23
窗口函数可以计算一定 记录范围内、一定值域内、或者一段时间内的累计和以及移动平均值等等.之所以使用窗口这个术语,是因为对结果的处理使用了一个滑动的查询结果集范围。
窗口可以与下面这些函数结合使用:sum(),avg(),max(),min(),count(),variance()和stddev();窗口也可以和first_value()与last_value()结合使用,这时候返回窗口中的第一个值和最后一个值。
先看下面列子
1 计算累计和
  下面这个查询通过执行累计和操作计算出2003年从一月到12月的累计销量。注意每月的销量都会加到累计值中,这样累计和在每个月结束时都会增长
select month,
       sum(amount) as month_amount,
       sum(sum(amount)) over (order by month rows between unbounded preceding and current row)
as cumulative_amount
  from all_sales
 where year=2003
 group by month
 order by month

结果集显示如下:
id monthmonth_amountcumulative_amount1195525.5595525.5522116671.6212197.1533160307.92372505.0744175998.8548503.8755154349.44702853.3166124951.36827804.6777170296.16998100.8388212735.681210836.5199199609.681410446.191010264480.791674926.981111160221.981835148.961212137336.171972485.13

现在分析一下这个表达式
1 sum(amount) 计算出销量的总和。外部的sum()计算累计销量。
2 order by month按照月份对查询读取的记录进行排序
3 rows between unbounded preceding and current row定义了窗口的行;窗口的终点是当前行。
 rows between unbounded preceding and current row也可以是rows unbounded preceding 
因此整个表达式的意思是从查询读取的第一行开始,计算每月的销量的累计和
每次处理窗口的一行记录时,都是从该窗口的第一条记录开始。每一行记录出来完之后,就将当前行的数量加到累计和中,并向下移动窗口的终点到下一行。然后继续处理,直到查询读取的最后一行也被处理为止。

下面这个查询使用累计和来计算2003年6月到12月的累计销量。注意使用rows unbounded preceding 来隐式地说明窗口的终点是当前行:
select month,
       sum(amount) as mount_amount,
       sum(sum(amount)) over( order by month rows unbounded preceding) as cumulative_amount
  from all_sales
 where year=2003
   and month between 6 and 12
 group by month
 order by month
 
下面这个查询计算本月与前3个月之间销量的移动平均值

select month,
       sum(amount) as month_amount,
       avg(sum(amount)) over (order by month rows between 3 preceding and current row) as moving_average
  from all_sales
 where year=2003
 group by month
 order by month

结果显示
id monthmonth_amountmoving_average1195525.5595525.5522116671.6106098.57533160307.92124168.356744175998.8137125.967555154349.44151831.9466124951.36153901.8877170296.16156398.9488212735.68165583.1699199609.68176898.221010264480.79211780.57751111160221.98209262.03251212137336.17190412.155

现在分解一下这个表达式:
1sum(amount) 计算出销量的总和。外部的avg()计算平均值
2 order by month按照月份对查询读出的记录进行排序
3 rows between 3 preceding and current row定义了窗口的起点为当前记录的前面第三条记录;窗口的终点为当前记录。也可以使用rows 3 preceding提前隐式的指定窗口大小,所得到的查询结果完全相同。
       因此,整个表达式的意思就是计算当前月份和此前三个月内的销量移动平均值。由于最开始的两个月可用的数据少于三个月,因此它们的移动平均值只是基于可用的月份计算的。
       该窗口的起点和终点都是始于查询读取的的行#1;每次处理一行时,窗口的终点就向下移动。但是只有当行#4处理完毕之后,窗口的起点才向下移动,从此之后,每当一条记录处理完毕时,窗口的起点也会向下移动。整个过程一直持续到查询读取的最后一条记录被处理为止。
---------------------------------------------------------------------------
 

3 计算中心平均值
下面这个查询计算当前月份前、后各一个月内的销量移动平均值:
select month,
       sum(amount) as month_amount,
       avg(sum(amount)) over (order by month rows between 1 preceding and 1 following) as moving_average
  from all_sales 
 where year=2003
 group by month
 order by month
现在分析这个表达式
rows between 1 preceding and 1 following定义了窗口的起点是当前记录之前的那条记录。窗口的终点是当前记录之后的那条记录。
因此整个表达式的意思就是计算当前月、前一个月、后一个月的销量移动平均值。由于第一个月和最后一个月可以参与计算的数据都少于三个月,因此移动平均值的计算只基于可用的数据。
---------------------------------------------------------------------------
 
 

4 用first_value()和last_value()获取第一条记录和最后一条记录
  first_value()和last_value()函数可以获取第一行和最后一行的数据。下面这个查询用first_value()和last_value()获取前一个月和最后一个月的销量:

select month,
       sum(amount) as mount_amount,
       first_value(sum(amount) )over (order by month rows between 1 preceding and 1 following) as previous_month_amount,
       last_value(sum(amount)) over (order by month rows between 1 preceding and 1 following) as next_month_amount
  from all_sales
 where year=2003
 group by month
 order by month

结果集:
id monthmonth_amountprevious_month_amountnext_month_amount1195525.559165525.551671.622116671.69605525.551307.9233160307.9217116671.65998.844175998.811560307.924349.4455154349.4412175998.84951.3666124951.361154349.4470296.1677170296.162124951.3612735.6888212735.681170296.1699609.6899199609.682212735.6864480.791010264480.79199609.68160221.981111160221.98264480.79137336.171212137336.17160221.98137336.17


下面这个查询将当前月份的销量除以前一个月的销量(保存在curr_div_prev列中),并将当前月份的销量除以下一个月的销量(保存在curr_dive_next列中):
select month,
       sum(amount) as mount_amount,
       sum(amount)/first_value(sum(amount) )over (order by month rows between 1 preceding and 1 following) as curr_div_prev,
       sum(amount)/last_value(sum(amount)) over (order by month rows between 1 preceding and 1 following) as curr_div_next
  from all_sales
 where year=2003
 group by month
 order by month
 
结果集:
id monthmonth_amountcurr_div_prevcurr_div_next1195525.5510.81875580722116671.61.2213653830.72779685533160307.921.3740097850.91084666544175998.81.0978796311.14026199355154349.440.8769914341.23527619166124951.360.8095355580.73372975677170296.161.3628996110.80050586788212735.681.2492100821.06575833499199609.680.938299020.7547227911010264480.791.32498981.6507147771111160221.980.6057981751.1666408061212137336.170.8571618581
0 0