PostgreSQL 窗口函數 ( Window Functions ) 如何使用?


一、為什么要有窗口函數


我們直接用例子來說明,這里有一張學生考試成績表testScore

現在有個需求,需要查詢的時候多出一列subject_avg_score,為此科目所有人的平均成績,好跟每個人的成績做對比。

傳統方法肯定是用聚合,但是寫起來很麻煩也很累贅,這時候窗口函數就排上了用場。

因為窗口函數不會像聚合一樣將參與計算的行合並成一行輸出,而是將計算出來的結果帶回到了計算行上。

二、窗口函數的使用


1、聚合和窗口函數的區別

聚合:聚合函數(sum,min,avg……) + GROUP BY

窗口函數:聚合函數(sum,min,avg……) + OVER ( …… )

2、使用

還用上面的例子:

(1) 取每個不同科目的平均值subject_avg_score [這正是上面提到的需求]

這里的 OVER 里用到了 PARTITION BY

SELECT *, 
       avg("score") OVER (PARTITION BY "subject") as "subject_avg_score"
FROM "testScore"  

(2) 取所有成績的平均值subject_avg_score

這里的 OVER 里為空

SELECT *, 
       avg("score") OVER () as "subject_avg_score"
FROM "testScore"  

(3) 取此人該科目成績班上排第幾名subject_rank_score

這里的 OVER 里用到了 PARTITION BY + ORDER BY

ORDER BY 只能用在一些特殊的聚合函數里,比如這里的 rank()

SELECT *, 
        avg("score") OVER (PARTITION BY "subject") as "subject_avg_score",
				rank() OVER (PARTITION BY "subject" ORDER BY "score" DESC) as "subject_rank_score" 
FROM "testScore"  

拓展知識:rank()、dense_rank()、row_number() 區別

rank() 最適合用來做排名的功能,它是若兩人並列第一,那第三個人就排名第三

dense_rank() 跟 rank() 的區別是,若兩人並列第一,那第三個人緊隨其后排名第二

row_number() 則單純是序號,所以不會出現多個人並列的情況。

(4) 提取 OVER 變量

如果在 sql 里寫了很多重復的 OVER(),可以提取成一個 window 變量,簡化代碼。

SELECT *, 
        avg("score") OVER window_frame as "subject_avg_score",
        avg("score") OVER window_frame as "subject_avg_score_2",
        avg("score") OVER window_frame as "subject_avg_score_3"
FROM "testScore"  
window window_frame as (PARTITION BY "subject")


參考資料

官方文檔:http://www.postgres.cn/docs/9.3/tutorial-window.html

Postgresql窗口函數(一)

Postgresql窗口函數(二)


免責聲明!

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



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