Oracle SQL高級編程——分析函數(窗口函數)全面講解

參見《Oracle SQL高級編程》

概述

分析函數是以一定的方法在一個與當前行相關的結果子集中進行計算,也稱爲窗口函數。
一般結構爲
Function(arg1 , arg2 ……) over(partition by clause order by clause windowing clause )

Windowing clause : rows | range between start_expr and end_expr
Start_expr is unbounded preceding | current row | n preceding | n following
End_expr is unbounded following | current row | n preceding | n following
不是所有的分析函數都支持開窗子句。

創建測試表

SH@ prod> create table sales_fact  as 
  2  select country_name country , country_subregion region , prod_name product , calendar_year year , calendar_week_number week , 
  3  sum(amount_sold) sale , sum(amount_sold*
  4  (case when mod(rownum , 10 ) = 0 then 1.4 
  5  when mod(rownum , 5)= 0 then 0.6
  6  when mod(rownum , 2)= 0 then 0.9
  7  when mod(rownum , 2)=1 then 1.2 
  8  else 1 end ) ) receipts 
  9  from sales , times , customers , countries , products 
 10  where sales.time_id = times.time_id and 
 11  sales.prod_id = products.prod_id and
 12  sales.cust_id = customers.cust_id and
 13  customers.country_id = countries.country_id 
 14  group by country_name , country_subregion , prod_name , calendar_year , calendar_week_number ;

Table created.

把聚合函數當作分析函數使用

分析函數列只是一列數值,每一行對應一個值,對於查詢的其它方面沒有任何影響。

從以下查詢可以得出以下幾點:
1.over分區條件中的列可以不在select列表中,但是必須在數據源中。
2.over排序條件中的列可以不在select列表中,但是必須在數據源中。
3.over排序條件是對所在分區中的數據進行排序,與select語句中的排序無關。但是會影響到分析函數的結果。
4.over中的開窗條件的範圍一般僅限於分區本身。rows between unbounded preceding and current row表示從分區的最開始到當前行。
5.分析函數的數據來自結果集(施加了where條件之後的)。

下面的查詢中的分析列表示該年從開始到該周的銷售累計。

SH@ prod> select year , week , sale , 
  2  sum(sale) over( partition by region , year  
  3  order by week 
  4  rows between unbounded preceding and current row ) running_sum_ytd 
  5  from sales_fact 
  6  where country in ('Australia') and product='Xtend Memory' and week < 10 
  7  order by year , week ;

      YEAR       WEEK       SALE RUNNING_SUM_YTD
---------- ---------- ---------- ---------------
      1998          1      58.15           58.15
      1998          2      29.39           87.54
      1998          3      29.49          117.03
      1998          4      29.49          146.52
      1998          5       29.8          176.32
      1998          6      58.78           235.1
      1998          9      58.78          293.88
      1999          1      53.52           53.52
      1999          3       94.6          148.12
      1999          4       40.5          188.62
      1999          5      80.01          268.63
      1999          6       40.5          309.13
      1999          8     103.11          412.24
      1999          9      53.34          465.58
      2000          1       46.7            46.7
      2000          3      93.41          140.11
      2000          4      46.54          186.65
      2000          5       46.7          233.35
      2000          7       70.8          304.15
      2000          8      46.54          350.69
      2001          1      92.26           92.26
      2001          2     118.38          210.64
      2001          3      47.24          257.88
      2001          4      256.7          514.58
      2001          5      93.44          608.02
      2001          6      22.44          630.46
      2001          7      69.96          700.42

      YEAR       WEEK       SALE RUNNING_SUM_YTD
---------- ---------- ---------- ---------------
      2001          8      46.06          746.48
      2001          9      92.67          839.15

29 rows selected.

結果與上面相同,只是排序不同方式,分析列看起來就沒有規律了。

SH@ prod> select year , week , sale , 
  2  sum(sale) over( partition by region , year  
  3  order by week 
  4  rows between unbounded preceding and current row ) running_sum_ytd 
  5  from sales_fact 
  6  where country in ('Australia') and product='Xtend Memory' and week < 10 
  7  order by year , sale ;

      YEAR       WEEK       SALE RUNNING_SUM_YTD
---------- ---------- ---------- ---------------
      1998          2      29.39           87.54
      1998          4      29.49          146.52
      1998          3      29.49          117.03
      1998          5       29.8          176.32
      1998          1      58.15           58.15
      1998          6      58.78           235.1
      1998          9      58.78          293.88
      1999          4       40.5          188.62
      1999          6       40.5          309.13
      1999          9      53.34          465.58
      1999          1      53.52           53.52
      1999          5      80.01          268.63
      1999          3       94.6          148.12
      1999          8     103.11          412.24
      2000          4      46.54          186.65
      2000          8      46.54          350.69
      2000          1       46.7            46.7
      2000          5       46.7          233.35
      2000          7       70.8          304.15
      2000          3      93.41          140.11
      2001          6      22.44          630.46
      2001          8      46.06          746.48
      2001          3      47.24          257.88
      2001          7      69.96          700.42
      2001          1      92.26           92.26
      2001          9      92.67          839.15
      2001          5      93.44          608.02

      YEAR       WEEK       SALE RUNNING_SUM_YTD
---------- ---------- ---------- ---------------
      2001          2     118.38          210.64
      2001          4      256.7          514.58

29 rows selected.

分區中的排序選取不恰當,則分析列結果沒有什麼意義了。分區開窗排序的選取與分析列的結果密切相關。

SH@ prod> select year , week , sale , 
  2  sum(sale) over( partition by  region , year  
  3  order by sale
  4  rows between unbounded preceding and current row ) running_sum_ytd 
  5  from sales_fact 
  6  where country in ('Australia') and product='Xtend Memory' and week < 10 
  7  order by  year , week ;

      YEAR       WEEK       SALE RUNNING_SUM_YTD
---------- ---------- ---------- ---------------
      1998          1      58.15          176.32
      1998          2      29.39           29.39
      1998          3      29.49           88.37
      1998          4      29.49           58.88
      1998          5       29.8          118.17
      1998          6      58.78           235.1
      1998          9      58.78          293.88
      1999          1      53.52          187.86
      1999          3       94.6          362.47
      1999          4       40.5            40.5
      1999          5      80.01          267.87
      1999          6       40.5              81
      1999          8     103.11          465.58
      1999          9      53.34          134.34
      2000          1       46.7          186.48
      2000          3      93.41          350.69
      2000          4      46.54           46.54
      2000          5       46.7          139.78
      2000          7       70.8          257.28
      2000          8      46.54           93.08
      2001          1      92.26          277.96
      2001          2     118.38          582.45
      2001          3      47.24          115.74
      2001          4      256.7          839.15
      2001          5      93.44          464.07
      2001          6      22.44           22.44
      2001          7      69.96           185.7

      YEAR       WEEK       SALE RUNNING_SUM_YTD
---------- ---------- ---------- ---------------
      2001          8      46.06            68.5
      2001          9      92.67          370.63

29 rows selected.

分析函數的執行計劃

雖然有分析函數還是隻需要一次全表掃描,但是需要排序。
WINDOW SORT是分析函數的典型特徵。

SH@ prod> explain plan for 
  2  select year , week , sale , 
  3  sum(sale) over( partition by  region , year  
  4  order by sale
  5  rows between unbounded preceding and current row ) running_sum_ytd 
  6  from sales_fact 
  7  where country in ('Australia') and product='Xtend Memory' and week < 10 
  8  order by  year , week ;

Explained.

SH@ prod> select * from table(dbms_xplan.display()) ;

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
Plan hash value: 173857439

----------------------------------------------------------------------------------
| Id  | Operation           | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |            |    18 |  1890 |   311   (1)| 00:00:04 |
|   1 |  SORT ORDER BY      |            |    18 |  1890 |   311   (1)| 00:00:04 |
|   2 |   WINDOW SORT       |            |    18 |  1890 |   311   (1)| 00:00:04 |
|*  3 |    TABLE ACCESS FULL| SALES_FACT |    18 |  1890 |   309   (1)| 00:00:04 |
----------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - filter("COUNTRY"='Australia' AND "PRODUCT"='Xtend Memory' AND
              "WEEK"<10)

Note
-----
   - dynamic sampling used for this statement (level=2)   說明該表還沒有統計信息。

20 rows selected.

不加分析列,只是少了一步window sort。

SH@ prod> explain plan for 
  2  select year , week , sale 
  3  from sales_fact 
  4  where country in ('Australia') and product='Xtend Memory' and week < 10 
  5  order by  year , week ;

Explained.

SH@ prod> select * from table(dbms_xplan.display()) ;

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
Plan hash value: 1978576542

---------------------------------------------------------------------------------
| Id  | Operation          | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |            |    18 |  1584 |   310   (1)| 00:00:04 |
|   1 |  SORT ORDER BY     |            |    18 |  1584 |   310   (1)| 00:00:04 |
|*  2 |   TABLE ACCESS FULL| SALES_FACT |    18 |  1584 |   309   (1)| 00:00:04 |
---------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("COUNTRY"='Australia' AND "PRODUCT"='Xtend Memory' AND
              "WEEK"<10)

Note
-----
   - dynamic sampling used for this statement (level=2)

19 rows selected.

如何使窗口充滿整個分區

SH@ prod> select year , week , sale , max(sale) over(partition by product , country , region , year 
  2  order by week 
  3  rows between unbounded preceding and unbounded following )
  4  max_sale
  5  from sales_fact 
  6  where country in ( 'Australia') and product = 'Xtend Memory' and week < 10
  7  order by product , country , year , week ;

      YEAR       WEEK       SALE   MAX_SALE
---------- ---------- ---------- ----------
      1998          1      58.15      58.78
      1998          2      29.39      58.78
      1998          3      29.49      58.78
      1998          4      29.49      58.78
      1998          5       29.8      58.78
      1998          6      58.78      58.78
      1998          9      58.78      58.78
      1999          1      53.52     103.11
      1999          3       94.6     103.11
      1999          4       40.5     103.11
      1999          5      80.01     103.11
      1999          6       40.5     103.11
      1999          8     103.11     103.11
      1999          9      53.34     103.11
      2000          1       46.7      93.41
      2000          3      93.41      93.41
      2000          4      46.54      93.41
      2000          5       46.7      93.41
      2000          7       70.8      93.41
      2000          8      46.54      93.41
      2001          1      92.26      256.7
      2001          2     118.38      256.7
      2001          3      47.24      256.7
      2001          4      256.7      256.7
      2001          5      93.44      256.7
      2001          6      22.44      256.7
      2001          7      69.96      256.7

      YEAR       WEEK       SALE   MAX_SALE
---------- ---------- ---------- ----------
      2001          8      46.06      256.7
      2001          9      92.67      256.7

29 rows selected.

兩個邊界都滑動的窗口

下面語句的窗口是往前兩週,加往後兩週,加當前周,一共五週。(到達邊界時窗口會自動縮小)

SH@ prod> select year , week , sale , max(sale) over(partition by product , country , region , year 
  2  order by week 
  3  rows between 2 preceding and 2 following )
  4  max_sale
  5  from sales_fact 
  6  where country in ( 'Australia') and product = 'Xtend Memory' and week < 10
  7  order by product , country , year , week ;

      YEAR       WEEK       SALE   MAX_SALE
---------- ---------- ---------- ----------
      1998          1      58.15      58.15
      1998          2      29.39      58.15
      1998          3      29.49      58.15
      1998          4      29.49      58.78
      1998          5       29.8      58.78
      1998          6      58.78      58.78
      1998          9      58.78      58.78
      1999          1      53.52       94.6
      1999          3       94.6       94.6
      1999          4       40.5       94.6
      1999          5      80.01     103.11
      1999          6       40.5     103.11
      1999          8     103.11     103.11
      1999          9      53.34     103.11
      2000          1       46.7      93.41
      2000          3      93.41      93.41
      2000          4      46.54      93.41
      2000          5       46.7      93.41
      2000          7       70.8       70.8
      2000          8      46.54       70.8  這裏只所以是70.8因爲窗口縮小了。
      2001          1      92.26     118.38
      2001          2     118.38      256.7
      2001          3      47.24      256.7
      2001          4      256.7      256.7
      2001          5      93.44      256.7
      2001          6      22.44      256.7
      2001          7      69.96      93.44

      YEAR       WEEK       SALE   MAX_SALE
---------- ---------- ---------- ----------
      2001          8      46.06      92.67
      2001          9      92.67      92.67

29 rows selected.

默認窗口是什麼?

一看便知。

SH@ prod> select year , week , sale , max(sale) over(partition by product , country , region , year 
  2  order by week )
  3  max_sale
  4  from sales_fact 
  5  where country in ( 'Australia') and product = 'Xtend Memory' and week < 10
  6  order by product , country , year , week ;

      YEAR       WEEK       SALE   MAX_SALE
---------- ---------- ---------- ----------
      1998          1      58.15      58.15
      1998          2      29.39      58.15
      1998          3      29.49      58.15
      1998          4      29.49      58.15
      1998          5       29.8      58.15
      1998          6      58.78      58.78
      1998          9      58.78      58.78
      1999          1      53.52      53.52
      1999          3       94.6       94.6
      1999          4       40.5       94.6
      1999          5      80.01       94.6
      1999          6       40.5       94.6
      1999          8     103.11     103.11
      1999          9      53.34     103.11
      2000          1       46.7       46.7
      2000          3      93.41      93.41
      2000          4      46.54      93.41
      2000          5       46.7      93.41
      2000          7       70.8      93.41
      2000          8      46.54      93.41
      2001          1      92.26      92.26
      2001          2     118.38     118.38
      2001          3      47.24     118.38
      2001          4      256.7      256.7
      2001          5      93.44      256.7
      2001          6      22.44      256.7
      2001          7      69.96      256.7

      YEAR       WEEK       SALE   MAX_SALE
---------- ---------- ---------- ----------
      2001          8      46.06      256.7
      2001          9      92.67      256.7

29 rows selected.

Lead和Lag(不支持開窗的函數)

有開窗語句時會報這樣的錯

rows between 2 preceding and 2 following )
*
ERROR at line 3:
ORA-00907: missing right parenthesis

LEAD是求下一個,而不是前一個。在分區的下邊界處,LEAD處回空值。

SH@ prod> select year , week , sale , lead(sale) over(partition by product , country , region , year 
  2  order by week  )
  3  former_sale
  4  from sales_fact 
  5  where country in ( 'Australia') and product = 'Xtend Memory' and week < 10
  6  order by product , country , year , week ;

      YEAR       WEEK       SALE FORMER_SALE
---------- ---------- ---------- -----------
      1998          1      58.15       29.39
      1998          2      29.39       29.49
      1998          3      29.49       29.49
      1998          4      29.49        29.8
      1998          5       29.8       58.78
      1998          6      58.78       58.78
      1998          9      58.78
      1999          1      53.52        94.6
      1999          3       94.6        40.5
      1999          4       40.5       80.01
      1999          5      80.01        40.5
      1999          6       40.5      103.11
      1999          8     103.11       53.34
      1999          9      53.34
      2000          1       46.7       93.41
      2000          3      93.41       46.54
      2000          4      46.54        46.7
      2000          5       46.7        70.8
      2000          7       70.8       46.54
      2000          8      46.54
      2001          1      92.26      118.38
      2001          2     118.38       47.24
      2001          3      47.24       256.7
      2001          4      256.7       93.44
      2001          5      93.44       22.44
      2001          6      22.44       69.96
      2001          7      69.96       46.06

      YEAR       WEEK       SALE FORMER_SALE
---------- ---------- ---------- -----------
      2001          8      46.06       92.67
      2001          9      92.67

29 rows selected.

LAG求上一個,也就是前一個。在分區的上邊界處返回空值。

SH@ prod> select year , week , sale , lag(sale) over(partition by product , country , region , year 
  2  order by week  )
  3  former_sale
  4  from sales_fact 
  5  where country in ( 'Australia') and product = 'Xtend Memory' and week < 10
  6  order by product , country , year , week ;

      YEAR       WEEK       SALE FORMER_SALE
---------- ---------- ---------- -----------
      1998          1      58.15
      1998          2      29.39       58.15
      1998          3      29.49       29.39
      1998          4      29.49       29.49
      1998          5       29.8       29.49
      1998          6      58.78        29.8
      1998          9      58.78       58.78
      1999          1      53.52
      1999          3       94.6       53.52
      1999          4       40.5        94.6
      1999          5      80.01        40.5
      1999          6       40.5       80.01
      1999          8     103.11        40.5
      1999          9      53.34      103.11
      2000          1       46.7
      2000          3      93.41        46.7
      2000          4      46.54       93.41
      2000          5       46.7       46.54
      2000          7       70.8        46.7
      2000          8      46.54        70.8
      2001          1      92.26
      2001          2     118.38       92.26
      2001          3      47.24      118.38
      2001          4      256.7       47.24
      2001          5      93.44       256.7
      2001          6      22.44       93.44
      2001          7      69.96       22.44

      YEAR       WEEK       SALE FORMER_SALE
---------- ---------- ---------- -----------
      2001          8      46.06       69.96
      2001          9      92.67       46.06

29 rows selected.

複雜的Lead和Lag

Lead和lag函數的第一參數爲返回的列,第二參數爲相隔行數(非負),第三個參數爲不存在時的默認值(可以指定爲當前行的值)。

SH@ prod> select year , week , sale , lag(sale , 2 , 0 ) over(partition by product , country , region , year 
  2  order by week  )
  3  former_sale
  4  from sales_fact 
  5  where country in ( 'Australia') and product = 'Xtend Memory' and week < 10
  6  order by product , country , year , week ;

      YEAR       WEEK       SALE FORMER_SALE
---------- ---------- ---------- -----------
      1998          1      58.15           0
      1998          2      29.39           0
      1998          3      29.49       58.15
      1998          4      29.49       29.39
      1998          5       29.8       29.49
      1998          6      58.78       29.49
      1998          9      58.78        29.8
      1999          1      53.52           0
      1999          3       94.6           0
      1999          4       40.5       53.52
      1999          5      80.01        94.6
      1999          6       40.5        40.5
      1999          8     103.11       80.01
      1999          9      53.34        40.5
      2000          1       46.7           0
      2000          3      93.41           0
      2000          4      46.54        46.7
      2000          5       46.7       93.41
      2000          7       70.8       46.54
      2000          8      46.54        46.7
      2001          1      92.26           0
      2001          2     118.38           0
      2001          3      47.24       92.26
      2001          4      256.7      118.38
      2001          5      93.44       47.24
      2001          6      22.44       256.7
      2001          7      69.96       93.44

      YEAR       WEEK       SALE FORMER_SALE
---------- ---------- ---------- -----------
      2001          8      46.06       22.44
      2001          9      92.67       69.96

29 rows selected.

將默認值指定爲當前行的值。

SH@ prod> select year , week , sale , lag(sale , 2 , sale ) over(partition by product , country , region , year 
  2  order by week  )
  3  former_sale
  4  from sales_fact 
  5  where country in ( 'Australia') and product = 'Xtend Memory' and week < 10
  6  order by product , country , year , week ;

      YEAR       WEEK       SALE FORMER_SALE
---------- ---------- ---------- -----------
      1998          1      58.15       58.15
      1998          2      29.39       29.39
      1998          3      29.49       58.15
      1998          4      29.49       29.39
      1998          5       29.8       29.49
      1998          6      58.78       29.49
      1998          9      58.78        29.8
      1999          1      53.52       53.52
      1999          3       94.6        94.6
      1999          4       40.5       53.52
      1999          5      80.01        94.6
      1999          6       40.5        40.5
      1999          8     103.11       80.01
      1999          9      53.34        40.5
      2000          1       46.7        46.7
      2000          3      93.41       93.41
      2000          4      46.54        46.7
      2000          5       46.7       93.41
      2000          7       70.8       46.54
      2000          8      46.54        46.7
      2001          1      92.26       92.26
      2001          2     118.38      118.38
      2001          3      47.24       92.26
      2001          4      256.7      118.38
      2001          5      93.44       47.24
      2001          6      22.44       256.7
      2001          7      69.96       93.44

      YEAR       WEEK       SALE FORMER_SALE
---------- ---------- ---------- -----------
      2001          8      46.06       22.44
      2001          9      92.67       69.96

29 rows selected.

LEAD與LAG關於數據缺口的問題

LAG(sale , 10 ) 這表示與它相隔10行的數據,可是我想訪問的10周前的數據。如果中間數據有缺口會出現嚴重的問題。

FIRST_VALUE和LAST_VALUE

這兩個函數都可以與order by條件配合得到最大值和最小值。
First_value返回窗口中的第一個值。Ignore nulls表示忽略空值,如果第一個是空值返回第二個。

SH@ prod> select year , week , sale , first_value(sale ignore nulls) over(partition by product , country , region , year 
  2  order by week  
  3  rows between unbounded preceding and unbounded following )
  4  former_sale
  5  from sales_fact 
  6  where country in ( 'Australia') and product = 'Xtend Memory' and week < 10
  7  order by product , country , year , week ;

      YEAR       WEEK       SALE FORMER_SALE
---------- ---------- ---------- -----------
      1998          1      58.15       58.15
      1998          2      29.39       58.15
      1998          3      29.49       58.15
      1998          4      29.49       58.15
      1998          5       29.8       58.15
      1998          6      58.78       58.15
      1998          9      58.78       58.15
      1999          1      53.52       53.52
      1999          3       94.6       53.52
      1999          4       40.5       53.52
      1999          5      80.01       53.52
      1999          6       40.5       53.52
      1999          8     103.11       53.52
      1999          9      53.34       53.52
      2000          1       46.7        46.7
      2000          3      93.41        46.7
      2000          4      46.54        46.7
      2000          5       46.7        46.7
      2000          7       70.8        46.7
      2000          8      46.54        46.7
      2001          1      92.26       92.26
      2001          2     118.38       92.26
      2001          3      47.24       92.26
      2001          4      256.7       92.26
      2001          5      93.44       92.26
      2001          6      22.44       92.26
      2001          7      69.96       92.26

      YEAR       WEEK       SALE FORMER_SALE
---------- ---------- ---------- -----------
      2001          8      46.06       92.26
      2001          9      92.67       92.26

29 rows selected. 

Last_value返回窗口中的最後一個值。Respect nulls表示識別空值,如果最後一個是空值也將其返回。

SH@ prod> select year , week , sale , last_value(sale respect nulls) over(partition by product , country , region , year 
  2  order by week  
  3  rows between unbounded preceding and unbounded following )
  4  former_sale
  5  from sales_fact 
  6  where country in ( 'Australia') and product = 'Xtend Memory' and week < 10
  7  order by product , country , year , week ;

      YEAR       WEEK       SALE FORMER_SALE
---------- ---------- ---------- -----------
      1998          1      58.15       58.78
      1998          2      29.39       58.78
      1998          3      29.49       58.78
      1998          4      29.49       58.78
      1998          5       29.8       58.78
      1998          6      58.78       58.78
      1998          9      58.78       58.78
      1999          1      53.52       53.34
      1999          3       94.6       53.34
      1999          4       40.5       53.34
      1999          5      80.01       53.34
      1999          6       40.5       53.34
      1999          8     103.11       53.34
      1999          9      53.34       53.34
      2000          1       46.7       46.54
      2000          3      93.41       46.54
      2000          4      46.54       46.54
      2000          5       46.7       46.54
      2000          7       70.8       46.54
      2000          8      46.54       46.54
      2001          1      92.26       92.67
      2001          2     118.38       92.67
      2001          3      47.24       92.67
      2001          4      256.7       92.67
      2001          5      93.44       92.67
      2001          6      22.44       92.67
      2001          7      69.96       92.67

      YEAR       WEEK       SALE FORMER_SALE
---------- ---------- ---------- -----------
      2001          8      46.06       92.67
      2001          9      92.67       92.67

29 rows selected.

NTH_VALUE訪問分區別的任意指定行

FIRST_VALUE相當於NTH_VALUE(sale , 1 )或者NTH_VALUE(sale , 1 )from first respect nulls。
可以與排序配合求第幾大,第幾小。

SH@ prod> select year , week , sale , nth_value(sale , 1 ) from last ignore nulls over(partition by product , country , region , year 
  2  order by week  
  3  rows between unbounded preceding and unbounded following )
  4  former_sale
  5  from sales_fact 
  6  where country in ( 'Australia') and product = 'Xtend Memory' and week < 10
  7  order by product , country , year , week ;

      YEAR       WEEK       SALE FORMER_SALE
---------- ---------- ---------- -----------
      1998          1      58.15       58.78
      1998          2      29.39       58.78
      1998          3      29.49       58.78
      1998          4      29.49       58.78
      1998          5       29.8       58.78
      1998          6      58.78       58.78
      1998          9      58.78       58.78
      1999          1      53.52       53.34
      1999          3       94.6       53.34
      1999          4       40.5       53.34
      1999          5      80.01       53.34
      1999          6       40.5       53.34
      1999          8     103.11       53.34
      1999          9      53.34       53.34
      2000          1       46.7       46.54
      2000          3      93.41       46.54
      2000          4      46.54       46.54
      2000          5       46.7       46.54
      2000          7       70.8       46.54
      2000          8      46.54       46.54
      2001          1      92.26       92.67
      2001          2     118.38       92.67
      2001          3      47.24       92.67
      2001          4      256.7       92.67
      2001          5      93.44       92.67
      2001          6      22.44       92.67
      2001          7      69.96       92.67

      YEAR       WEEK       SALE FORMER_SALE
---------- ---------- ---------- -----------
      2001          8      46.06       92.67
      2001          9      92.67       92.67

29 rows selected.

RANK函數(不能開窗,作用於整個分區)

必須有排序條件,rank就是根據order by條件中的列來定排名的。
RANK函數的排名中,如果出現並列,排名將不連續。
如:1 2(2) 4 5 6 7 8 9 。 如果有兩個第二名,那麼第三名就不存在了。
請注意空值,在排序子句中可以使用NULLS LAST來把空值放在最後面。

SH@ prod> select year , week , sale , rank() over(partition by product , country , region , year 
  2  order by sale )
  3  former_sale
  4  from sales_fact 
  5  where country in ( 'Australia') and product = 'Xtend Memory' and week < 10
  6  order by product , country , year , week ;

      YEAR       WEEK       SALE FORMER_SALE
---------- ---------- ---------- -----------
      1998          1      58.15           5   沒有3
      1998          2      29.39           1
      1998          3      29.49           2
      1998          4      29.49           2
      1998          5       29.8           4
      1998          6      58.78           6
      1998          9      58.78           6
      1999          1      53.52           4
      1999          3       94.6           6
      1999          4       40.5           1
      1999          5      80.01           5
      1999          6       40.5           1
      1999          8     103.11           7
      1999          9      53.34           3
      2000          1       46.7           3
      2000          3      93.41           6
      2000          4      46.54           1
      2000          5       46.7           3
      2000          7       70.8           5
      2000          8      46.54           1
      2001          1      92.26           5
      2001          2     118.38           8
      2001          3      47.24           3
      2001          4      256.7           9
      2001          5      93.44           7
      2001          6      22.44           1
      2001          7      69.96           4

      YEAR       WEEK       SALE FORMER_SALE
---------- ---------- ---------- -----------
      2001          8      46.06           2
      2001          9      92.67           6

29 rows selected.

DENSE_RANK(與RANK的區別在於排名一是連續的)

SH@ prod> select year , week , sale , dense_rank() over(partition by product , country , region , year 
  2  order by sale )
  3  former_sale
  4  from sales_fact 
  5  where country in ( 'Australia') and product = 'Xtend Memory' and week < 10
  6  order by product , country , year , week ;

      YEAR       WEEK       SALE FORMER_SALE
---------- ---------- ---------- -----------
      1998          1      58.15           4  第三名是存在的
      1998          2      29.39           1
      1998          3      29.49           2
      1998          4      29.49           2
      1998          5       29.8           3
      1998          6      58.78           5
      1998          9      58.78           5
      1999          1      53.52           3
      1999          3       94.6           5
      1999          4       40.5           1
      1999          5      80.01           4
      1999          6       40.5           1
      1999          8     103.11           6
      1999          9      53.34           2
      2000          1       46.7           2
      2000          3      93.41           4
      2000          4      46.54           1
      2000          5       46.7           2
      2000          7       70.8           3
      2000          8      46.54           1
      2001          1      92.26           5
      2001          2     118.38           8
      2001          3      47.24           3
      2001          4      256.7           9
      2001          5      93.44           7
      2001          6      22.44           1
      2001          7      69.96           4

      YEAR       WEEK       SALE FORMER_SALE
---------- ---------- ---------- -----------
      2001          8      46.06           2
      2001          9      92.67           6

29 rows selected.

ROW_NUMBER(不支持開窗,不確定性函數)

爲分區中的每一行指定一個遞增的編號,如果排序的列的值相同,誰先誰後是隨機的。

SH@ prod> select year , week , sale , row_number() over(partition by product , country , region , year 
  2  order by sale )
  3  former_sale
  4  from sales_fact 
  5  where country in ( 'Australia') and product = 'Xtend Memory' and week < 10
  6  order by product , country , year , sale ;

      YEAR       WEEK       SALE FORMER_SALE
---------- ---------- ---------- -----------
      1998          2      29.39           1
      1998          4      29.49           2
      1998          3      29.49           3
      1998          5       29.8           4
      1998          1      58.15           5
      1998          6      58.78           6
      1998          9      58.78           7
      1999          4       40.5           1
      1999          6       40.5           2
      1999          9      53.34           3
      1999          1      53.52           4
      1999          5      80.01           5
      1999          3       94.6           6
      1999          8     103.11           7
      2000          4      46.54           1
      2000          8      46.54           2
      2000          5       46.7           3
      2000          1       46.7           4
      2000          7       70.8           5
      2000          3      93.41           6
      2001          6      22.44           1
      2001          8      46.06           2
      2001          3      47.24           3
      2001          7      69.96           4
      2001          1      92.26           5
      2001          9      92.67           6
      2001          5      93.44           7

      YEAR       WEEK       SALE FORMER_SALE
---------- ---------- ---------- -----------
      2001          2     118.38           8
      2001          4      256.7           9

29 rows selected.

Ratio_to_report(當前行的值與分區總和的比值)

這個函數不支持排序和開窗。
求各周的銷量在每年中的比例以及在整個產品銷量中的比例。

SH@ prod> select year , week , sale ,
  2  trunc(100* ratio_to_report(sale) over(partition by year ) , 2) sales_yr , 
  3  trunc(100* ratio_to_report(sale) over() , 2 ) sales_prod 
  4  from sales_fact 
  5  where country in ('Australia') and product = 'Xtend Memory' and week < 10
  6  order by year , week ;

      YEAR       WEEK       SALE   SALES_YR SALES_PROD
---------- ---------- ---------- ---------- ----------
      1998          1      58.15      19.78       2.98
      1998          2      29.39         10        1.5
      1998          3      29.49      10.03       1.51
      1998          4      29.49      10.03       1.51
      1998          5       29.8      10.14       1.52
      1998          6      58.78         20       3.01
      1998          9      58.78         20       3.01
      1999          1      53.52      11.49       2.74
      1999          3       94.6      20.31       4.85
      1999          4       40.5       8.69       2.07
      1999          5      80.01      17.18        4.1
      1999          6       40.5       8.69       2.07
      1999          8     103.11      22.14       5.28
      1999          9      53.34      11.45       2.73
      2000          1       46.7      13.31       2.39
      2000          3      93.41      26.63       4.79
      2000          4      46.54      13.27       2.38
      2000          5       46.7      13.31       2.39
      2000          7       70.8      20.18       3.63
      2000          8      46.54      13.27       2.38
      2001          1      92.26      10.99       4.73
      2001          2     118.38       14.1       6.07
      2001          3      47.24       5.62       2.42
      2001          4      256.7      30.59      13.16
      2001          5      93.44      11.13       4.79
      2001          6      22.44       2.67       1.15
      2001          7      69.96       8.33       3.58

      YEAR       WEEK       SALE   SALES_YR SALES_PROD
---------- ---------- ---------- ---------- ----------
      2001          8      46.06       5.48       2.36
      2001          9      92.67      11.04       4.75

29 rows selected.

Percent_rank(排在前百分之幾)

用來求當前行的排名的相對百分位置。
比如你對人說自己是第10名,別人可能覺得沒什麼,如果是100000中的第10名,那就是前1/10000,那就非常牛了。
這個函數與RANK的推導公式爲:
PERCENT_RANK = (RANK - 1) / (N – 1) , N代表總行數。
RANK – 1代表排名大於自己的人數。
N – 1代表除自己以外的總人數。
總體的意思是除自己之外的其它中人,排名比自己高的人所佔的比例。

SH@ prod> select year , week , sale , rank() over(partition by product , country , region , year 
  2  order by sale )
  3  former_sale
  4  from sales_fact 
  5  where country in ( 'Australia') and product = 'Xtend Memory' and week < 10
  6  order by product , country , year , sale ;

      YEAR       WEEK       SALE FORMER_SALE
---------- ---------- ---------- -----------
      1998          2      29.39           1
      1998          4      29.49           2
      1998          3      29.49           2
      1998          5       29.8           4
      1998          1      58.15           5
      1998          6      58.78           6
      1998          9      58.78           6
      1999          4       40.5           1
      1999          6       40.5           1
      1999          9      53.34           3
      1999          1      53.52           4
      1999          5      80.01           5
      1999          3       94.6           6
      1999          8     103.11           7
      2000          4      46.54           1
      2000          8      46.54           1
      2000          5       46.7           3
      2000          1       46.7           3
      2000          7       70.8           5
      2000          3      93.41           6
      2001          6      22.44           1
      2001          8      46.06           2
      2001          3      47.24           3
      2001          7      69.96           4
      2001          1      92.26           5
      2001          9      92.67           6
      2001          5      93.44           7

      YEAR       WEEK       SALE FORMER_SALE
---------- ---------- ---------- -----------
      2001          2     118.38           8
      2001          4      256.7           9

29 rows selected.

SH@ prod> select year , week , sale , 100*percent_rank() over(partition by product , country , region , year 
  2  order by sale )
  3  former_sale
  4  from sales_fact 
  5  where country in ( 'Australia') and product = 'Xtend Memory' and week < 10
  6  order by product , country , year , sale ;

      YEAR       WEEK       SALE FORMER_SALE
---------- ---------- ---------- -----------
      1998          2      29.39           0
      1998          4      29.49  16.6666667
      1998          3      29.49  16.6666667
      1998          5       29.8          50
      1998          1      58.15  66.6666667
      1998          6      58.78  83.3333333
      1998          9      58.78  83.3333333
      1999          4       40.5           0
      1999          6       40.5           0
      1999          9      53.34  33.3333333
      1999          1      53.52          50
      1999          5      80.01  66.6666667
      1999          3       94.6  83.3333333
      1999          8     103.11         100
      2000          4      46.54           0
      2000          8      46.54           0
      2000          5       46.7          40
      2000          1       46.7          40
      2000          7       70.8          80
      2000          3      93.41         100
      2001          6      22.44           0
      2001          8      46.06        12.5
      2001          3      47.24          25
      2001          7      69.96        37.5
      2001          1      92.26          50
      2001          9      92.67        62.5
      2001          5      93.44          75

      YEAR       WEEK       SALE FORMER_SALE
---------- ---------- ---------- -----------
      2001          2     118.38        87.5
      2001          4      256.7         100

29 rows selected.

Percentile_cont(大體意思求排在某個百分比時所需的數值)

也可以說是,現在說這樣一個值,向分區裏面插入這個值,其排名在百分之N(percent_rank爲N%),求這個值。
如果有一個行的percent_rank正好等於N,那麼就是這個麼的值。如果沒有匹配的,則要計算概率最大的。

SH@ prod> select year , week , sale ,
  2  percentile_cont(0.5) within group(order by sale desc )over(partition by year) pc ,
  3  percent_rank() over( partition by year order by sale desc ) pr
  4  from sales_fact 
  5  where country in ('Australia') and product = 'Xtend Memory' and week < 11 ;

      YEAR       WEEK       SALE         PC         PR
---------- ---------- ---------- ---------- ----------
      1998         10     117.76     43.975          0
      1998          9      58.78     43.975 .142857143
      1998          6      58.78     43.975 .142857143
      1998          1      58.15     43.975 .428571429
      1998          5       29.8     43.975 .571428571
      1998          3      29.49     43.975 .714285714
      1998          4      29.49     43.975 .714285714
      1998          2      29.39     43.975          1
      1999          8     103.11      62.76          0
      1999          3       94.6      62.76 .142857143
      1999          5      80.01      62.76 .285714286
      1999         10         72      62.76 .428571429
      1999          1      53.52      62.76 .571428571
      1999          9      53.34      62.76 .714285714
      1999          6       40.5      62.76 .857142857
      1999          4       40.5      62.76 .857142857
      2000          3      93.41       46.7          0
      2000          7       70.8       46.7         .2
      2000          5       46.7       46.7         .4
      2000          1       46.7       46.7         .4
      2000          4      46.54       46.7         .8
      2000          8      46.54       46.7         .8
      2001          4      256.7      81.11          0
      2001          2     118.38      81.11 .111111111
      2001          5      93.44      81.11 .222222222
      2001          9      92.67      81.11 .333333333
      2001          1      92.26      81.11 .444444444

      YEAR       WEEK       SALE         PC         PR
---------- ---------- ---------- ---------- ----------
      2001          7      69.96      81.11 .555555556
      2001         10      69.05      81.11 .666666667
      2001          3      47.24      81.11 .777777778
      2001          8      46.06      81.11 .888888889
      2001          6      22.44      81.11          1

32 rows selected.

Percentile_disc(功能與Percentile_cont大體相同)

區別在於這個函數取到的值一定是在這個分區的行中的。
如果沒有匹配的,Percentile_disc會按照排序取上一個。

SH@ prod> select year , week , sale ,
  2  percentile_disc(0.5) within group(order by sale desc )over(partition by year) pc ,
  3  percent_rank() over( partition by year order by sale desc ) pr
  4  from sales_fact 
  5  where country in ('Australia') and product = 'Xtend Memory' and week < 11 ;

      YEAR       WEEK       SALE         PC         PR
---------- ---------- ---------- ---------- ----------
      1998         10     117.76      58.15          0
      1998          9      58.78      58.15 .142857143
      1998          6      58.78      58.15 .142857143
      1998          1      58.15      58.15 .428571429
      1998          5       29.8      58.15 .571428571
      1998          3      29.49      58.15 .714285714
      1998          4      29.49      58.15 .714285714
      1998          2      29.39      58.15          1
      1999          8     103.11         72          0
      1999          3       94.6         72 .142857143
      1999          5      80.01         72 .285714286
      1999         10         72         72 .428571429
      1999          1      53.52         72 .571428571
      1999          9      53.34         72 .714285714
      1999          6       40.5         72 .857142857
      1999          4       40.5         72 .857142857
      2000          3      93.41       46.7          0
      2000          7       70.8       46.7         .2
      2000          5       46.7       46.7         .4
      2000          1       46.7       46.7         .4
      2000          4      46.54       46.7         .8
      2000          8      46.54       46.7         .8
      2001          4      256.7      92.26          0
      2001          2     118.38      92.26 .111111111
      2001          5      93.44      92.26 .222222222
      2001          9      92.67      92.26 .333333333
      2001          1      92.26      92.26 .444444444

      YEAR       WEEK       SALE         PC         PR
---------- ---------- ---------- ---------- ----------
      2001          7      69.96      92.26 .555555556
      2001         10      69.05      92.26 .666666667
      2001          3      47.24      92.26 .777777778
      2001          8      46.06      92.26 .888888889
      2001          6      22.44      92.26          1

32 rows selected.

SH@ prod> select year , week , sale ,
  2  percentile_cont(0.5) within group(order by sale desc )over(partition by year) pc ,
  3  percent_rank() over( partition by year order by sale desc ) pr
  4  from sales_fact 
  5  where country in ('Australia') and product = 'Xtend Memory' and week < 11 ;

      YEAR       WEEK       SALE         PC         PR
---------- ---------- ---------- ---------- ----------
      1998         10     117.76     43.975          0
      1998          9      58.78     43.975 .142857143
      1998          6      58.78     43.975 .142857143
      1998          1      58.15     43.975 .428571429
      1998          5       29.8     43.975 .571428571
      1998          3      29.49     43.975 .714285714
      1998          4      29.49     43.975 .714285714
      1998          2      29.39     43.975          1
      1999          8     103.11      62.76          0
      1999          3       94.6      62.76 .142857143
      1999          5      80.01      62.76 .285714286
      1999         10         72      62.76 .428571429
      1999          1      53.52      62.76 .571428571
      1999          9      53.34      62.76 .714285714
      1999          6       40.5      62.76 .857142857
      1999          4       40.5      62.76 .857142857
      2000          3      93.41       46.7          0
      2000          7       70.8       46.7         .2
      2000          5       46.7       46.7         .4
      2000          1       46.7       46.7         .4
      2000          4      46.54       46.7         .8
      2000          8      46.54       46.7         .8
      2001          4      256.7      81.11          0
      2001          2     118.38      81.11 .111111111
      2001          5      93.44      81.11 .222222222
      2001          9      92.67      81.11 .333333333
      2001          1      92.26      81.11 .444444444

      YEAR       WEEK       SALE         PC         PR
---------- ---------- ---------- ---------- ----------
      2001          7      69.96      81.11 .555555556
      2001         10      69.05      81.11 .666666667
      2001          3      47.24      81.11 .777777778
      2001          8      46.06      81.11 .888888889
      2001          6      22.44      81.11          1

32 rows selected.

NTILE(類型於建立直方圖,不支持開窗)

將排序後的數據均勻分配到指定個數據桶中,返回桶編號,如果不能等分,各個桶中的行數最多相差一行。
在以後的處理中可以通過去除首桶或尾去除異常值。
注意:並不是按值分配的。

SH@ prod> select year , week , sale , 
  2  ntile(10) over(order by sale ) group#
  3  from sales_fact
  4  where country in ('Australia') and product = 'Xtend Memory' and year = 1998 order by year , sale;

      YEAR       WEEK       SALE     GROUP#
---------- ---------- ---------- ----------
      1998         50      28.76          1
      1998          2      29.39          1
      1998          4      29.49          1
      1998          3      29.49          1
      1998          5       29.8          2
      1998         43      57.52          2
      1998         35      57.52          2
      1998         40      57.52          2
      1998         46      57.52          3
      1998         27      57.52          3
      1998         45      57.52          3
      1998         44      57.52          3
      1998         47      57.72          4
      1998         29      57.72          4
      1998         28      57.72          4
      1998          1      58.15          4
      1998         41      58.32          5
      1998         51      58.32          5
      1998         14      58.78          5
      1998          9      58.78          5
      1998         15      58.78          6
      1998         17      58.78          6
      1998          6      58.78          6
      1998         19      58.98          6
      1998         21       59.6          7
      1998         12       59.6          7
      1998         52      86.38          7

      YEAR       WEEK       SALE     GROUP#
---------- ---------- ---------- ----------
      1998         34     115.44          8
      1998         39     115.84          8
      1998         42     115.84          8
      1998         38     115.84          9
      1998         23     117.56          9
      1998         18     117.56          9
      1998         26     117.56         10
      1998         10     117.76         10
      1998         48     172.56         10

36 rows selected.

Stddev計算標準差(方差的平方根,支持開窗)

SH@ prod> select year , week , sale , 
  2  stddev(sale) over(
  3  partition by product , country , region , year 
  4  order by sale desc 
  5  rows between 2 preceding and 2 following ) stddv
  6  from sales_fact
  7  where country in ('Australia') and product = 'Xtend Memory' and week < 10
  8  order by year , week ;

      YEAR       WEEK       SALE      STDDV
---------- ---------- ---------- ----------
      1998          1      58.15 15.8453416
      1998          2      29.39 .057735027
      1998          3      29.49 .178021534
      1998          4      29.49 12.7945918
      1998          5       29.8  15.815738
      1998          6      58.78  .36373067
      1998          9      58.78 14.3880654
      1999          1      53.52  22.178931
      1999          3       94.6 21.7319902
      1999          4       40.5 7.46550065
      1999          5      80.01 22.9761992
      1999          6       40.5 7.41317746
      1999          8     103.11 11.6825953
      1999          9      53.34 16.1305511
      2000          1       46.7 21.0022332
      2000          3      93.41 23.3589605
      2000          4      46.54 .092376043
      2000          5       46.7 10.8139207
      2000          7       70.8 22.4285538
      2000          8      46.54 .092376043
      2001          1      92.26 20.3811452
      2001          2     118.38 78.5152276
      2001          3      47.24 26.5077898
      2001          4      256.7  87.947194
      2001          5      93.44  71.309193
      2001          6      22.44 13.9900965
      2001          7      69.96 22.9124643

      YEAR       WEEK       SALE      STDDV
---------- ---------- ---------- ----------
      2001          8      46.06  19.407678
      2001          9      92.67 17.1409691

29 rows selected.

Listagg(把分區中的列按照順序拼接起來,不支持開窗)

SH@ prod> col stddv for a60
SH@ prod> select year , week , sale , 
  2  listagg(sale , ' , ')within group(order by sale desc) over(
  3  partition by product , country , region , year  ) stddv
  4  from sales_fact
  5  where country in ('Australia') and product = 'Xtend Memory' and week < 5
  6  order by year , week ;

      YEAR       WEEK       SALE STDDV
---------- ---------- ---------- ------------------------------------------------------------
      1998          1      58.15 58.15 , 29.49 , 29.49 , 29.39
      1998          2      29.39 58.15 , 29.49 , 29.49 , 29.39
      1998          3      29.49 58.15 , 29.49 , 29.49 , 29.39
      1998          4      29.49 58.15 , 29.49 , 29.49 , 29.39
      1999          1      53.52 94.6 , 53.52 , 40.5
      1999          3       94.6 94.6 , 53.52 , 40.5
      1999          4       40.5 94.6 , 53.52 , 40.5
      2000          1       46.7 93.41 , 46.7 , 46.54
      2000          3      93.41 93.41 , 46.7 , 46.54
      2000          4      46.54 93.41 , 46.7 , 46.54
      2001          1      92.26 256.7 , 118.38 , 92.26 , 47.24
      2001          2     118.38 256.7 , 118.38 , 92.26 , 47.24
      2001          3      47.24 256.7 , 118.38 , 92.26 , 47.24
      2001          4      256.7 256.7 , 118.38 , 92.26 , 47.24

14 rows selected.

分析函數對謂詞前推的影響

使用了分析函數的視圖,會影響視圖前推,因爲分析函數的結果是跨行引用得來的,如果對數據源進行的剪裁,結果可能會不一樣。

SH@ prod> create or replace view max_5_weeks_vw as 
  2  select country , product , region , year , week , sale ,
  3  max(sale) over(
  4  partition by product , country , region , year order by year , week 
  5  rows between 2 preceding and 2 following ) max_weeks_5
  6  from sales_fact ;

View created.

SH@ prod> select year , week , sale , max_weeks_5 from max_5_weeks_vw 
  2  where country in ('Australia' ) and product = 'Xtend Memory' 
  3  and region = 'Australia' and year = 2000 and week < 14 
  4  order by year , week ; 

      YEAR       WEEK       SALE MAX_WEEKS_5
---------- ---------- ---------- -----------
      2000          1       46.7       93.41
      2000          3      93.41       93.41
      2000          4      46.54       93.41
      2000          5       46.7       93.41
      2000          7       70.8       93.74
      2000          8      46.54       93.74
      2000         11      93.74       117.5
      2000         12      46.54      117.67
      2000         13      117.5      117.67

9 rows selected.

SH@ prod> explain plan for 
  2  select year , week , sale , max_weeks_5 from max_5_weeks_vw 
  3  where country in ('Australia' ) and product = 'Xtend Memory' 
  4  and region = 'Australia' and year = 2000 and week < 14 
  5  order by year , week ; 

Explained.

SH@ prod> select * from table(dbms_xplan.display());

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
Plan hash value: 4167461139

--------------------------------------------------------------------------------------
| Id  | Operation           | Name           | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |                |    90 |  5220 |   310   (1)| 00:00:04 |
|*  1 |  VIEW               | MAX_5_WEEKS_VW |    90 |  5220 |   310   (1)| 00:00:04 |
|   2 |   WINDOW SORT       |                |    90 |  9450 |   310   (1)| 00:00:04 |
|*  3 |    TABLE ACCESS FULL| SALES_FACT     |    90 |  9450 |   309   (1)| 00:00:04 |
--------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("WEEK"<14)
   3 - filter("COUNTRY"='Australia' AND "PRODUCT"='Xtend Memory' AND
              "REGION"='Australia' AND "YEAR"=2000)

Note
-----
   - dynamic sampling used for this statement (level=2)

21 rows selected.

對比沒有分析函數的視圖。直接將謂詞推入到視圖裏面。

SH@ prod> create or replace view max_5_weeks_vw1 as 
  2  select country , product , region , year , week , sale 
  3  from sales_fact ;

View created.

SH@ prod> explain plan for 
  2  select year , week , sale from max_5_weeks_vw1 
  3  where country in ('Australia' ) and product = 'Xtend Memory' 
  4  and region = 'Australia' and year = 2000 and week < 14 
  5  order by year , week ;

Explained.

SH@ prod> select * from table(dbms_xplan.display());

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
Plan hash value: 1978576542

---------------------------------------------------------------------------------
| Id  | Operation          | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |            |     1 |   105 |   310   (1)| 00:00:04 |
|   1 |  SORT ORDER BY     |            |     1 |   105 |   310   (1)| 00:00:04 |
|*  2 |   TABLE ACCESS FULL| SALES_FACT |     1 |   105 |   309   (1)| 00:00:04 |
---------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("COUNTRY"='Australia' AND "PRODUCT"='Xtend Memory' AND
              "REGION"='Australia' AND "YEAR"=2000 AND "WEEK"<14)

Note
-----
   - dynamic sampling used for this statement (level=2)

19 rows selected.

分析函數用在動態SQL中

SH@ prod> create or replace procedure analytic_dynamic_prc ( part_col_string varchar2 , v_country varchar2 , v_product varchar2 ) 
  2  is
  3  type numtab is table of number(18 , 2) index by binary_integer ;
  4  l_year numtab ;
  5  l_week numtab ;
  6  l_sale numtab ;
  7  l_rank numtab ;
  8  l_sql_string varchar2(512) ;
  9  begin
 10  l_sql_string := 'select * from ( select year , week , sale , rank() over( partition by ' || part_col_string 
 11  || ' order by sale desc ) sales_rank from sales_fact where country in (' 
 12  || chr(39) || v_country || chr(39) 
 13  || ' ) and product = ' || chr(39) || v_product || chr(39) 
 14  || 'order by product , country , year , week ) where sales_rank <= 10  order by 1,4' ;
 15  execute immediate l_sql_string bulk collect into l_year , l_week , l_sale , l_rank ;
 16  for i in 1..l_year.count loop
 17  dbms_output.put_line( l_year(i) || ' | ' || l_week(i) || ' | ' || l_sale(i) || ' | ' || l_rank(i) ) ;
 18  end loop ;
 19  end ;
 20  /

Procedure created.

SH@ prod> exec analytic_dynamic_prc('product , country , region' , 'Australia' , 'Xtend Memory' ) ;
1998 | 48 | 172.56 | 9
2000 | 46 | 246.74 | 3
2000 | 21 | 187.48 | 5
2000 | 43 | 179.12 | 7
2000 | 34 | 178.52 | 8
2001 | 16 | 278.44 | 1
2001 | 4 | 256.7 | 2
2001 | 21 | 233.7 | 4
2001 | 48 | 182.96 | 6
2001 | 30 | 162.91 | 10
2001 | 14 | 162.91 | 10

PL/SQL procedure successfully completed.

分析函數的“嵌套”

分析函數不能直接嵌套,可能通過子查詢來實現。

select year , week , top_sale_year , 
lag( top_sale_year ) over ( order by year desc ) prev_top_sale_yer
from (
    select distinct 
        first_value(year) over (   這裏的作用不能用MAX代替,這裏取列與排序的列是不同的。
        partition by product , country , region , year 
        order by sale desc 
        rows between unbounded preceding and unbounded following ) year ,
        first_value(week) over (
        partition by product , country , region , year 
        order by sale desc 
        rows between unbounded preceding and unbounded following ) week ,
        first_value(sale) over (
        partition by product , country , region , year 
        order by sale desc 
        rows between unbounded preceding and unbounded following ) top_sale_year
    from sales_fact 
    where country in ('Australia') and product = 'Xtend Memory' )
order by year , week ;

執行結果。

SH@ prod> select year , week , top_sale_year , 
  2  lag( top_sale_year ) over ( order by year desc ) prev_top_sale_yer
  3  from (
  4  select distinct 
  5  first_value(year) over (
  6  partition by product , country , region , year 
  7  order by sale desc 
  8  rows between unbounded preceding and unbounded following ) year ,
  9  first_value(week) over (
 10  partition by product , country , region , year 
 11  order by sale desc 
 12  rows between unbounded preceding and unbounded following ) week ,
 13  first_value(sale) over (
 14  partition by product , country , region , year 
 15  order by sale desc 
 16  rows between unbounded preceding and unbounded following ) top_sale_year
 17  from sales_fact 
 18  where country in ('Australia') and product = 'Xtend Memory' )
 19  order by year , week ;

      YEAR       WEEK TOP_SALE_YEAR PREV_TOP_SALE_YER
---------- ---------- ------------- -----------------
      1998         48        172.56            148.12
      1999         17        148.12            246.74
      2000         46        246.74            278.44
      2001         16        278.44

分析函數的並行

查看上一節中的語句的執行計劃。

SH@ prod> explain plan for 
  2  select year , week , top_sale_year , 
  3  lag( top_sale_year ) over ( order by year desc ) prev_top_sale_yer
  4  from (
  5  select distinct 
  6  first_value(year) over (
  7  partition by product , country , region , year 
  8  order by sale desc 
  9  rows between unbounded preceding and unbounded following ) year ,
 10  first_value(week) over (
 11  partition by product , country , region , year 
 12  order by sale desc 
 13  rows between unbounded preceding and unbounded following ) week ,
 14  first_value(sale) over (
 15  partition by product , country , region , year 
 16  order by sale desc 
 17  rows between unbounded preceding and unbounded following ) top_sale_year
 18  from sales_fact 
 19  where country in ('Australia') and product = 'Xtend Memory' )
 20  order by year , week ;

Explained.

SH@ prod> select * from table(dbms_xplan.display());

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
Plan hash value: 2124823565

-------------------------------------------------------------------------------------
| Id  | Operation              | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |            |   197 |  7683 |   313   (2)| 00:00:04 |
|   1 |  SORT ORDER BY         |            |   197 |  7683 |   313   (2)| 00:00:04 |
|   2 |   WINDOW SORT          |            |   197 |  7683 |   313   (2)| 00:00:04 |
|   3 |    VIEW                |            |   197 |  7683 |   311   (1)| 00:00:04 |
|   4 |     HASH UNIQUE        |            |   197 | 20685 |   311   (1)| 00:00:04 |
|   5 |      WINDOW SORT       |            |   197 | 20685 |   311   (1)| 00:00:04 |
|*  6 |       TABLE ACCESS FULL| SALES_FACT |   197 | 20685 |   309   (1)| 00:00:04 |
-------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   6 - filter("COUNTRY"='Australia' AND "PRODUCT"='Xtend Memory')

Note
-----
   - dynamic sampling used for this statement (level=2)

22 rows selected.
(注意DISTINCT操作採用的是HASH UNIQUE而不是排序)

爲上面的語句添加並行提示。

SH@ prod> explain plan for 
  2  select /*+ parallel(3)*/ year , week , top_sale_year , 
  3  lag( top_sale_year ) over ( order by year desc ) prev_top_sale_yer
  4  from (
  5  select distinct 
  6  first_value(year) over (
  7  partition by product , country , region , year 
  8  order by sale desc 
  9  rows between unbounded preceding and unbounded following ) year ,
 10  first_value(week) over (
 11  partition by product , country , region , year 
 12  order by sale desc 
 13  rows between unbounded preceding and unbounded following ) week ,
 14  first_value(sale) over (
 15  partition by product , country , region , year 
 16  order by sale desc 
 17  rows between unbounded preceding and unbounded following ) top_sale_year
 18  from sales_fact 
 19  where country in ('Australia') and product = 'Xtend Memory' )
 20  order by year , week ;

Explained.

SH@ prod> set linesize 180
SH@ prod> select * from table(dbms_xplan.display());

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 2880616722

----------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                        | Name       | Rows  | Bytes | Cost (%CPU)| Time     |    TQ  |IN-OUT| PQ Distrib |
----------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                 |            |   197 |  7683 |   119   (5)| 00:00:02 |        |      |            |
|   1 |  SORT ORDER BY                   |            |   197 |  7683 |   119   (5)| 00:00:02 |        |      |            |
|   2 |   WINDOW BUFFER                  |            |   197 |  7683 |   119   (5)| 00:00:02 |        |      |            |
|   3 |    PX COORDINATOR                |            |       |       |            |          |        |      |            |
|   4 |     PX SEND QC (ORDER)           | :TQ10003   |   197 |  7683 |   119   (5)| 00:00:02 |  Q1,03 | P->S | QC (ORDER) |
|   5 |      SORT ORDER BY               |            |   197 |  7683 |   119   (5)| 00:00:02 |  Q1,03 | PCWP |            |
|   6 |       PX RECEIVE                 |            |   197 |  7683 |   117   (3)| 00:00:02 |  Q1,03 | PCWP |            |
|   7 |        PX SEND RANGE             | :TQ10002   |   197 |  7683 |   117   (3)| 00:00:02 |  Q1,02 | P->P | RANGE      |
|   8 |         VIEW                     |            |   197 |  7683 |   117   (3)| 00:00:02 |  Q1,02 | PCWP |            |
|   9 |          HASH UNIQUE             |            |   197 | 20685 |   117   (3)| 00:00:02 |  Q1,02 | PCWP |            |
|  10 |           PX RECEIVE             |            |   197 | 20685 |   117   (3)| 00:00:02 |  Q1,02 | PCWP |            |
|  11 |            PX SEND HASH          | :TQ10001   |   197 | 20685 |   117   (3)| 00:00:02 |  Q1,01 | P->P | HASH       |
|  12 |             WINDOW SORT          |            |   197 | 20685 |   117   (3)| 00:00:02 |  Q1,01 | PCWP |            |
|  13 |              PX RECEIVE          |            |   197 | 20685 |   114   (0)| 00:00:02 |  Q1,01 | PCWP |            |
|  14 |               PX SEND HASH       | :TQ10000   |   197 | 20685 |   114   (0)| 00:00:02 |  Q1,00 | P->P | HASH       |
|  15 |                PX BLOCK ITERATOR |            |   197 | 20685 |   114   (0)| 00:00:02 |  Q1,00 | PCWC |            |
|* 16 |                 TABLE ACCESS FULL| SALES_FACT |   197 | 20685 |   114   (0)| 00:00:02 |  Q1,00 | PCWP |            |
----------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------


PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  16 - filter("COUNTRY"='Australia' AND "PRODUCT"='Xtend Memory')

Note
-----
   - dynamic sampling used for this statement (level=2)
   - Degree of Parallelism is 3 because of hint

33 rows selected.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章