oracle窗口函數的使用

窗口函數可以計算一定 記錄範圍內、一定值域內、或者一段時間內的累計和以及移動平均值等等.之所以使用窗口這個術語,是因爲對結果的處理使用了一個滑動的查詢結果集範圍。
窗口可以與下面這些函數結合使用: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  month month_amount cumulative_amount
1 1 95525.55 95525.55
2 2 116671.6 212197.15
3 3 160307.92 372505.07
4 4 175998.8 548503.87
5 5 154349.44 702853.31
6 6 124951.36 827804.67
7 7 170296.16 998100.83
8 8 212735.68 1210836.51
9 9 199609.68 1410446.19
10 10 264480.79 1674926.98
11 11 160221.98 1835148.96
12 12 137336.17 1972485.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  month month_amount moving_average
1 1 95525.55 95525.55
2 2 116671.6 106098.575
3 3 160307.92 124168.3567
4 4 175998.8 137125.9675
5 5 154349.44 151831.94
6 6 124951.36 153901.88
7 7 170296.16 156398.94
8 8 212735.68 165583.16
9 9 199609.68 176898.22
10 10 264480.79 211780.5775
11 11 160221.98 209262.0325
12 12 137336.17 190412.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  month month_amount previous_month_amount next_month_amount
1 1 95525.55 95525.55 116671.6
2 2 116671.6 95525.55 160307.92
3 3 160307.92 116671.6 175998.8
4 4 175998.8 160307.92 154349.44
5 5 154349.44 175998.8 124951.36
6 6 124951.36 1154349.44 170296.16
7 7 170296.16 124951.36 212735.68
8 8 212735.68 1170296.16 199609.68
9 9 199609.68 2212735.68 264480.79
10 10 264480.79 199609.68 160221.98
11 11 160221.98 264480.79 137336.17
12 12 137336.17 160221.98 137336.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  month month_amount curr_div_prev curr_div_next
1 1 95525.55 1 0.818755807
2 2 116671.6 1.221365383 0.727796855
3 3 160307.92 1.374009785 0.910846665
4 4 175998.8 1.097879631 1.140261993
5 5 154349.44 0.876991434 1.235276191
6 6 124951.36 0.809535558 0.733729756
7 7 170296.16 1.362899611 0.800505867
8 8 212735.68 1.249210082 1.065758334
9 9 199609.68 0.93829902 0.754722791
10 10 264480.79 1.3249898 1.650714777
11 11 160221.98 0.605798175 1.166640806
12 12 137336.17 0.857161858 1

轉載:http://blog.chinaunix.net/uid-7450061-id-2054536.html
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章