Oracle 之 分析函數


一、分析函數 

  1、分析函數
  分析函數是Oracle專門用於解決復雜報表統計需求的功能強大的函數,它可以在數據中進行分組然后計算基於組的某種統計值,並且每一組的每一行都可以返回一個統計值。

  2、分析函數和聚合函數的區別
  普通的聚合函數用group by分組,每個分組返回一個統計值,而分析函數采用partition by分組,並且每組每行都可以返回一個統計值。

      3、分析函數的形式
  分析函數帶有一個開窗函數over(),包含分析子句 。

  分析子句又由下面三部分組成:
  partition by :分組子句,表示分析函數的計算范圍,不同的組互不相干;
  ORDER BY: 排序子句,表示分組后,組內的排序方式;
  ROWS/RANGE:窗口子句,是在分組(PARTITION BY)后,組內的子分組(也稱窗口),此時分析函數的計算范圍窗口,而不是PARTITON。窗口有兩種,ROWS和RANGE;

  使用形式如下:

OVER(PARTITION BY xxx PORDER BY yyy ROWS BETWEEN rowStart AND rowEnd)

  注:窗口子句在這里我只說rows方式的窗口,range方式和滑動窗口也不提。

二、OVER() 函數

  1、sql 查詢語句的 order by 和 OVER() 函數中的 ORDER BY 的執行順序
  分析函數是在整個sql查詢結束后(sql語句中的order by的執行比較特殊)再進行的操作, 也就是說sql語句中的order by也會影響分析函數的執行結果:

  [1] 兩者一致:如果sql語句中的order by滿足分析函數分析時要求的排序,那么sql語句中的排序將先執行,分析函數在分析時就不必再排序;
  [2] 兩者不一致:如果sql語句中的order by不滿足分析函數分析時要求的排序,那么sql語句中的排序將最后在分析函數分析結束后執行排序。

  2、分析函數中的分組/排序/窗口
      分析函數包含三個分析子句:分組(partition by), 排序(order by), 窗口(rows/range)
      窗口就是分析函數分析時要處理的數據范圍,就拿sum來說,它是sum窗口中的記錄而不是整個分組中的記錄,因此我們在想得到某個欄位的累計值時,我們需要把窗口指定到該分組中的第一行數據到當前行, 如果你指定該窗口從該分組中的第一行到最后一行,那么該組中的每一個sum值都會一樣,即整個組的總和。

  [A] range是邏輯窗口(值):是指定當前行對應值的范圍取值,列數不固定,只要行值在范圍內,對應列都包含在內。

  如:SUM(id) OVER ( ORDER BY id RANGE BETWEEN 1 PRECEING AND 2 FOLLOWING ),分析:
  當id=1時,是 1-1<=id<=1+2 的所有id值求和,即sum=1+1+3=5(取id為1,1,3);
  當id=3時,是3-1<=id<=3+2 的所有id值求和,即sum=3(取id為3);


  [B] rows是物理窗口(行):即根據order by 子句排序后,取的前N行及后N行的數據計算(與當前行的值無關,只與排序后的行號相關),

  如:SUM(id) OVER ( ORDER BY id ROWS BETWEEN 1 PRECEING AND 2 FOLLOWING ),是取前1行到后2行的數據求和,分析:
  當id=1時,前一行沒數,,后二行是第3行,就是1到3行;
  當id=3時,前一行是第2行,后二行是第5行,就是2到5行;

  2.1 帶有窗口子句

  窗口子句,是在分組(PARTITION BY)后,組內的子分組(也稱窗口),此時分析函數的計算范圍窗口,而不是PARTITON。窗口有兩種,ROWS和RANGE。若使用窗口子句,必須有ORDER BY 子句。
  窗口子句中經常用到指定行:第一行(unbounded preceding),當前行(current row),最后一行(unbounded following),以及前num1行(num1 preceding )和 后num2行(num2 following)。
  窗口子句不能單獨出現,必須有order by子句時才能出現,如:

last_value(sal) 
over(partition by deptno 
     order by sal 
     rows between unbounded preceding and unbounded following)

  以上示例指定窗口為整個分組。而出現order by子句的時候,不一定要有窗口子句,但效果會很不一樣,此時的窗口默認是當前組的第一行到當前行!

  2.2 當省略窗口子句時:
  [1] 如果存在order by則默認的窗口是unbounded preceding and current row  --當前組的第一行到當前行
  [2] 如果同時省略order by則默認的窗口是unbounded preceding and unbounded following  --整個組

             
  2.3 如果省略分組,則把全部記錄當成一個組:
  [1] 如果存在order by則默認窗口是unbounded preceding and current row   --當前組的第一行到當前行

  [2]如果這時省略order by則窗口默認為unbounded preceding and unbounded following  --整個組

三、常用分析函數

  1、排名函數

  函數為每條記錄產生一個從1開始至n的自然數,n的值可能小於等於記錄的總數。這3個函數的唯一區別在於當碰到相同數據時的排名策略。

  1.1 row_number() over()

  row_number()返回一個唯一的值,當碰到相同數據時,排名按照記錄集中記錄的順序依次遞增。
  1.2 rank() over()

  rank()返回一個唯一的值,當碰到相同的數據時,此時所有相同數據的排名是一樣的,同時會在最后一條相同記錄和下一條不同記錄的排名之間空出排名。
  1.3 dense_rank() over()

  dense_rank()返回一個唯一的值,當碰到相同數據時,此時所有相同數據的排名都是一樣的,同時會在最后一條相同記錄和下一條不同記錄的排名之間緊鄰遞增。

  2、聚合函數

  2.1 count() over()
  2.2 max() over()
  2.3 min() over()
  2.4 sum() over()
  2.5 avg() over()

 

  3、 求最值對應的其他屬性
  3.1 first_value() over():第一個值
  3.2 last_value() over():最后一個值

  4、求之前或之后的第N行

  注:行比較分析函數lead和lag無window(窗口)子句。

  lag(arg1,arg2,arg3) 和 lead(arg1,arg2,arg3) 可以在一次查詢中取出同一字段的前n行的數據和后n行的值。這種操作可以使用對相同表的表連接來實現,不過使用lag和lead有更高的效率。
  [1] arg1:參數是列名,
  [2] arg2:參數是偏移的offset,
  [3] arg3:參數是超出記錄窗口時的默認值。
  4.1 lag() over()

    lag()函數向下偏移。
  4.2 lead() over()

    lead()函數是向上偏移。

  舉例如下:
  select *  from kkk;                                         
                                                                 
        ID NAME                                                  
---------- --------------------                                  
         1 1name                                                 
         2 2name                                                 
         3 3name                                                 
         4 4name                                                 
         5 5name                                                 
  select id,name,lag(name,1,0) over(order by id) from kkk;
                                                                 
        ID NAME                 LAG(NAME,1,0)OVER(ORDERBYID)     
---------- -------------------- ----------------------------     
         1 1name                0                                
         2 2name                1name                            
         3 3name                2name                            
         4 4name                3name                            
         5 5name                4name

  select id,name,lead(name,1,0) over(order by id) from kkk;
                                                                 
        ID NAME                 LEAD(NAME,1,0)OVER(ORDERBYID)    
---------- -------------------- -----------------------------    
         1 1name                2name                            
         2 2name                3name                            
         3 3name                4name                            
         4 4name                5name                            
         5 5name                0

  select id,name,lead(name,2,0) over(order by id) from kkk;                                                                                                              
        ID NAME                 LEAD(NAME,2,0)OVER(ORDERBYID)    
---------- -------------------- -----------------------------    
         1 1name                3name                            
         2 2name                4name                            
         3 3name                5name                            
         4 4name                0                                
         5 5name                0 
  select id,name,lead(name,1,'linjiqin') over(order by id) from kkk;                                 
                                                                                 
        ID NAME                 LEAD(NAME,1,'ALSDFJLASDJFSAF')                   
---------- -------------------- ------------------------------                   
         1 1name                2name                                            
         2 2name                3name                                            
         3 3name                4name                                            
         4 4name                5name                                            
         5 5name                linjiqin  

---------------------------------------------------------------------------------------

  5、排列組合函數,只能用在 GROUP BY 后邊

  5.1 group by rollup(a, b, c):
  
首先會對(a、b、c)進行group by,
  然后再對(a、b)進行group by,
  其后再對(a)進行group by,
  最后對全表進行匯總操作。

  5.2 group by cube(a, b, c):
  首先會對(a、b、c)進行group by,
  然后依次是(a、b),(a、c),(a),(b、c),(b),(c),
  最后對全表進行匯總操作。

  5.3 示例如下:

  5.3.1 普通 group by 分組
  sql> select owner, index_type, status, count(*) from t where owner like 'SY%' group by owner, index_type, status;

  

  5.3.2 GROUP BY ROLLUP(A, B, C):
  首先會對(A、B、C)進行GROUP BY,
  然后再對(A、B)進行GROUP BY,
  其后再對(A)進行GROUP BY,
  最后對全表進行匯總操作。
  select owner, index_type, status, count(*) from t where owner like 'SY%' group by ROLLUP(owner, index_type, status);

  

  5.3.3 GROUP BY CUBE(A, B, C):
  首先會對(A、B、C)進行GROUP BY,
  然后依次是(A、B),(A、C),(A),(B、C),(B),(C),
  最后對全表進行匯總操作。

  select owner, index_type, status, count(*) from t where owner like 'SY%' group by cube(owner, index_type, status);

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM