Oracle開發之:視窗函式 (轉) rows between unbounded preceding and current row
目錄
=========================================
1.視窗函式簡介
2.視窗函式示例-全統計
3.視窗函式進階-滾動統計(累積/均值)
4.視窗函式進階-根據時間範圍統計
5.視窗函式進階-first_value/last_value
6.視窗函式進階-比較相鄰記錄
一、視窗函式簡介:
到目前為止,我們所學習的分析函式在計算/統計一段時間內的資料時特別有用,但是假如計算/統計需要隨著遍歷記錄集的每一條記錄而進行呢?舉些例子來說:
①列出每月的訂單總額以及全年的訂單總額
②列出每月的訂單總額以及截至到當前月的訂單總額
③列出上個月、當月、下一月的訂單總額以及全年的訂單總額
④列出每天的營業額及一週來的總營業額
⑤列出每天的營業額及一週來每天的平均營業額
仔細回顧一下前面我們介紹到的分析函式,我們會發現這些需求和前面有一些不同:前面我們介紹的分析函式用於計算/統計一個明確的階段/記錄集,而這裡有部分需求例如2,需要隨著遍歷記錄集的每一條記錄的同時進行統計。
也即是說:統計不止發生一次,而是發生多次。統計不至發生在記錄集形成後,而是發生在記錄集形成的過程中。
這就是我們這次要介紹的視窗函式的應用了。它適用於以下幾個場合:
①通過指定一批記錄:例如從當前記錄開始直至某個部分的最後一條記錄結束
②通過指定一個時間間隔:例如在交易日之前的前30天
③通過指定一個範圍值:例如所有佔到當前交易量總額5%的記錄
二、視窗函式示例-全統計:
下面我們以需求:列出每月的訂單總額以及全年的訂單總額為例,來看看視窗函式的應用。
【1】測試環境:
名稱 是否為空? 型別
-- --------------------- -------- ----------------
MONTH NUMBER ( 2 )
TOT_SALES NUMBER
SQL >
【2】測試資料:
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之後的所有記錄,實際情況如何讓我們通過示例來驗證:
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的意思針對當前所有記錄的前一條、後一條記錄,也就是表中的所有記錄。那麼假如我們直接指定從第一條記錄開始直至末尾呢?看看下面的結果:
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就可以了。
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行。
現在我們能得到滾動的銷售總額了!下面這個統計結果看起來更加完美,它展現了所有我們需要的資料:
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 語句就統計了當天銷售額和五天內的評價銷售額:
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
個月的銷售平均值,這兩個函式就可以派上用場了。
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
子句,它能夠通過和當前記錄的相對位置而被應用,在比較同一個相鄰的記錄集內兩條相鄰記錄的時候特別有用。
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 月為基準。
相關文章
- 視窗函式 (轉) rows between unbounded preceding and current row函式
- Oracle開發專題之:OLAP 函式 (rows 2 preceding / unbounded preceding)Oracle函式
- Oracle NTH_VALUE分析函式及ROWS BETWEEN UNBOUNDED PRECEDING AND子句Oracle函式
- [轉]OLAP 函式 (rows 2 preceding / unbounded preceding)函式
- OLAP 函式 (rows 2 preceding / unbounded preceding)函式
- 視窗函式 row_number 去重複函式
- (轉)Oracle語法之OVER(PARTITION BY)及開窗函式Oracle函式
- Oracle分析函式與視窗函式Oracle函式
- Oracle分析函式之開窗函式over()詳解Oracle函式
- Oracle 語法之 OVER (PARTITION BY ..) 及開窗函式 轉載Oracle函式
- 【函式】oracle視窗函式over()的理解函式Oracle
- MySQL中的FOUND_ROWS()與ROW_COUNT()函式MySql函式
- ROW_NUMBER 開窗函式最佳化方案(Oracle && PostgreSQL 效能比對)函式OracleSQL
- 視窗函式函式
- oracle的分析函式over 及開窗函式Oracle函式
- SQL視窗分析函式使用詳解系列三之偏移量類視窗函式SQL函式
- PostgreSQL:視窗函式SQL函式
- SQL 視窗函式SQL函式
- Mysql視窗函式MySql函式
- Hive視窗函式Hive函式
- [clickhouse] Clickhouse之開窗函式篇函式
- 【Analytic】分析函式之ROW_NUMBER函式函式
- 分析函式視窗子句 RANGE/ROWS 差別函式
- oracle 分析函式之(rank()/dense_rank()/row_number())Oracle函式
- 呼叫API函式設計ABOUT視窗 (轉)API函式
- 【Oracle SQL】months_between與trunc函式OracleSQL函式
- oracle的分析函式over(Partition by...) 及開窗函式Oracle函式
- JavaScript視窗功能指南之發揮視窗特徵 (轉)JavaScript特徵
- hive視窗函式使用Hive函式
- SparkSQL 開窗函式SparkSQL函式
- Spark 開窗函式Spark函式
- SparkSQL開窗函式SparkSQL函式
- hive視窗分析函式使用詳解系列二之分組排序視窗函式Hive函式排序
- 與SQL視窗函式相同SQL函式
- PostgreSQL>視窗函式的用法SQL函式
- MySQL視窗函式彙總MySql函式
- hive05_視窗函式Hive函式
- 分析函式用法及視窗子句 range/rows差別函式