mysql窗口函數


窗口函數(數據分析-SQL高階(窗口函數) - 嗶哩嗶哩 (bilibili.com)
窗口函數也稱為OLAP(Online Analytical Processing)函數,意思是對數據庫數據進行實時分析處理,窗口函數在Oracle和SQL Server 中也被稱為分析函數,窗口函數語法如下

<窗口函數> OVER ([PARTITION BY <列清單>]           ORDER BY <排序用列清單> [框架])

語法中<>中的內容不可省略,[]中的內容可以省略。即PARTIION BY和框架可以省略,ORDER BY 不可以省略。框架對匯總范圍進行限定。

(ROWS | RANGE) BETWEEN (UNBOUNDED | [num]) PRECEDING AND ([num] PRECEDING | CURRENT ROW | (UNBOUNDED | [num]) FOLLOWING) (ROWS | RANGE) BETWEEN CURRENT ROW AND (CURRENT ROW | (UNBOUNDED | [num]) FOLLOWING) (ROWS | RANGE) BETWEEN [num] FOLLOWING AND (UNBOUNDED | [num]) FOLLOWING

窗口函數: 1)可以作為窗口函數的聚合函數。

SUM :求和

MIN :最小值

MAX :最大值

AVG :平均值

COUNT :計數

2)專用窗口函數

RANK :跳躍排序,排序:1,1,3

DENSE_RANK :連續排序,排序:1,1,2

ROW_NUMBER:沒有重復值的排序,排序:1,2,3

FIRST_VALUE :返回組中數據窗口的第一個值

LAST_VALUE :返回組中數據窗口的最后一個值。

LAG :LAG(col,n,DEFAULT) 用於統計窗口內往上第n行值。

LEAD :LEAD(col,n,DEFAULT) 用於統計窗口內往下第n行值。

窗口函數實操
先創建一張產品表

create table product ( product_id int(4) COMMENT 'ID', product_name varchar(10) COMMENT '產品名稱', product_type varchar(10) COMMENT '產品類型', sale_price int(4) COMMENT '價格' )ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='產品清單'

插入數據

insert into product(product_id,product_name,product_type,sale_price) values(1,'叉子','廚房用具',500),(2,'擦菜板','廚房用具',880), (3,'菜刀','廚房用具',3000),(4,'高壓鍋','廚房用具',6800),(5,'T恤衫','衣服',1000),(6,'運動T恤','衣服',4000),(7,'圓珠筆','辦公用品',100),(8,'打孔器','辦公用品',500);

結果表如圖 

 

 

1)可以作為窗口函數的聚合函數。

sum求和(累計值)

SELECT product_id, product_name, product_type, sale_price, SUM(sale_price) OVER (PARTITION BY product_type ORDER BY sale_price range BETWEEN UNBOUNDED PRECEDING and current row ) AS current_sum FROM Product; 

 

 SELECT product_id, product_name, product_type, sale_price, SUM(sale_price) OVER ( ORDER BY sale_price ) AS current_sum FROM Product; # 上邊語句和下邊語句結果相同 SELECT product_id, product_name, product_type, sale_price, SUM(sale_price) OVER ( ORDER BY sale_price range BETWEEN UNBOUNDED PRECEDING and current row ) AS current_sum FROM Product; 

 

 

注:默認框架為 range BETWEEN UNBOUNDED PRECEDING and current row,row和range的區別是rows按照行進行計算,如當求第一行的時候,求和為第一行-第一行,當求第二行的時候,求和為第一行-第二行;而range是按照值進行計算,如sale_price, 當sale_price=100,求和范圍為100-100,當sale_price=500,求和范圍為100-500。

SELECT product_id, product_name, product_type, sale_price, SUM(sale_price) OVER ( ORDER BY sale_price rows BETWEEN UNBOUNDED PRECEDING and current row ) AS current_sum FROM Product; 

 

 

MIN、MAX、AVG、COUNT

SELECT product_id, product_name, product_type, sale_price, MIN(sale_price) OVER ( PARTITION BY product_type ORDER BY sale_price  ) AS current_min, MAX(sale_price) OVER ( PARTITION BY product_type ORDER BY sale_price  ) AS current_max, AVG(sale_price) OVER ( PARTITION BY product_type ORDER BY sale_price  ) AS current_avg, COUNT(sale_price) OVER ( PARTITION BY product_type ORDER BY sale_price  ) AS current_count FROM Product; 

 

 

注:默認框架為range BETWEEN UNBOUNDED PRECEDING and current row*,range是按照值進行計算的,以count來進行講述,第一組第一行count計算的范圍為sale_price值,就是100-100的就一個值,計數1;第一組第二行count計算的范圍為100-500,計數2;第二組第一行count計算的范圍為500-500,計數2。后續類似。

2)專用窗口函數

RANK、DENSE_RANK、ROW_NUMBER

SELECT product_id, product_name, product_type, sale_price, rank() OVER ( PARTITION BY product_type ORDER BY sale_price rows BETWEEN 2 PRECEDING and current row ) AS current_rk, dense_rank() OVER ( PARTITION BY product_type ORDER BY sale_price  ) AS current_drk, row_number() OVER ( PARTITION BY product_type ORDER BY sale_price  ) AS current_rn FROM Product; 

 

 

注:rank函數排序是可以跳躍的,dense_rank函數排序是順序的,row_number函數排序是按照行數。

FIRST_VALUE、LAST_VALUE

SELECT product_id, product_name, product_type, sale_price, FIRST_VALUE(sale_price) OVER ( PARTITION BY product_type ORDER BY sale_price  ) AS current_FV, LAST_VALUE(sale_price) OVER ( PARTITION BY product_type ORDER BY sale_price  ) AS current_LV FROM Product; 

 

 

LAG 、LEAD。

SELECT product_id, product_name, product_type, sale_price, LAG(sale_price,1) OVER ( PARTITION BY product_type ORDER BY sale_price  ) AS current_LAG, LEAD(sale_price,1) OVER ( PARTITION BY product_type ORDER BY sale_price  ) AS current_LEAD FROM Product; 

 

 

總結
窗口函數兼具GROUP BY 子句的分組功能和ORDER BY子句的排序功能,但是PARTITION BY子句跟GROUP BY 不具備匯總功能,也就說PARTITION BY子句不會減少行數。

通過PARTITION BY 分組后的記錄集合稱為窗口。此處的窗口並非“窗戶”的意思,而是代表范圍。這也是“窗口函數”名稱的由來。

 

一、hive窗口函數語法

在前言中我們已經說了avg()、sum()、max()、min()是分析函數,而over()才是窗口函數,下面我們來看看over()窗口函數的語法結構、及常與over()一起使用的分析函數

1、over()窗口函數的語法結構
2、常與over()一起使用的分析函數
3、窗口函數總結

1、over()窗口函數的語法結構

分析函數 over(partition by 列名 order by 列名 rows between 開始位置 and 結束位置)

over()函數中包括三個函數:包括分區partition by 列名、排序order by 列名、指定窗口范圍rows between 開始位置 and 結束位置。我們在使用over()窗口函數時,over()函數中的這三個函數可組合使用也可以不使用。

over()函數中如果不使用這三個函數,窗口大小是針對查詢產生的所有數據,如果指定了分區,窗口大小是針對每個分區的數據。

 

1.1、over()函數中的三個函數講解

order by
order by是排序的意思,是該窗口中的
A、partition by
partition by可理解為group by 分組。over(partition by 列名)搭配分析函數時,分析函數按照每一組每一組的數據進行計算的。

B、rows between 開始位置 and 結束位置
是指定窗口范圍,比如第一行到當前行。而這個范圍是隨着數據變化的。over(rows between 開始位置 and 結束位置)搭配分析函數時,分析函數按照這個范圍進行計算的。
窗口范圍說明:
我們常使用的窗口范圍是ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW(表示從起點到當前行),常用該窗口來計算累加。

PRECEDING:往前
FOLLOWING:往后
CURRENT ROW:當前行
UNBOUNDED:起點(一般結合PRECEDING,FOLLOWING使用)
UNBOUNDED PRECEDING 表示該窗口最前面的行(起點)
UNBOUNDED FOLLOWING:表示該窗口最后面的行(終點)
比如說:
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW(表示從起點到當前行)
ROWS BETWEEN 2 PRECEDING AND 1 FOLLOWING(表示往前2行到往后1行)
ROWS BETWEEN 2 PRECEDING AND 1 CURRENT ROW(表示往前2行到當前行)
ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING(表示當前行到終點)

2、常與over()一起使用的分析函數:

2.1、聚合類

avg()、sum()、max()、min()

2.1、排名類

row_number()按照值排序時產生一個自增編號,不會重復(如:1、2、3、4、5、6)
rank() 按照值排序時產生一個自增編號,值相等時會重復,會產生空位(如:1、2、3、3、3、6)
dense_rank() 按照值排序時產生一個自增編號,值相等時會重復,不會產生空位(如:1、2、3、3、3、4)


2.1、其他類

lag(列名,往前的行數,[行數為null時的默認值,不指定為null]),以計算用戶上次購買時間,或者用戶下次購買時間。
lead(列名,往后的行數,[行數為null時的默認值,不指定為null])
ntile(n) 把有序分區中的行分發到指定數據的組中,各個組有編號,編號從1開始,對於每一行,ntile返回此行所屬的組的編號

3、窗口函數總結:

其實窗口函數邏輯比較繞,我們可以把窗口理解為對表中的數據進行分組,排序等計算。



 
 
 
 
 
 

含義:窗口函數也叫OLAP函數(Online Anallytical Processing,聯機分析處理),可以對數據進行實時分析處理。

作用:

  • 解決排名問題,e.g.每個班級按成績排名
  • 解決TOPN問題,e.g.每個班級前兩名的學生

語法:

select 窗口函數 over (partition by 用於分組的列名, order by 用於排序的列名

分類:

  • 專用窗口函數:rank(),dense_rank(),row_number()
  • 匯總函數:max(),min(),count(),sum(),avg()

注意:窗口函數是對where后者group by子句處理后的結果進行操作,因此按照SQL語句的運行順序,窗口函數一般放在select子句中。

 

窗口函數的用法

    1. 專用窗口函數

rank()函數

 

 

說明

  • rank()是排序函數,括號中不需要有參數;
  • 通過partition by將班級分類,相當於之前用過的group by子句功能,但是group by子句分類匯總會改變原數據的行數,而用窗口函數自救保持原行數;
  • 通過order by將成績降序排列,與之前學的order by子句用法一樣,后邊可以升序asc或者降序desc;

總結:

  • 窗口函數這里的“窗口”表示范圍,可以理解為將原數據划分范圍,即分組,然后用函數實現某些目的
  • 窗口函數有分組和排序的功能
  • 不減少原表的行數

 

2. 其他專用窗口函數:dense_rank/row_number

  • 用法與rank()函數相同

 

 

 

  • 當成績相同時,會存在並列的情況,主要區別是三個函數如何處理並列情況:

在rank()函數,如果有並列情況,會占用下一個名次的位置,比如,成績為100的學生有三個並列第一,那么99分的學生是第二名,通過rank()函數,名次是:1,1,1,4;

在dense()函數中,如果有並列的情況,不會占用下一個名詞,同用上個例子,名次是:1,1,1,2;

在row_number()函數中,會忽略並列的情況,同用上述例子,名次是:1,2,3,4;

 

 

 

 


免責聲明!

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



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