開窗函數主要分為2類:
1.排序開窗函數:
rank() over(partition by xxx order by yyy) //各分區按照yyy字段排序,如果yyy字段值一樣,則rank值一樣,且下一個序號為rank值加1,如1、2、2、3、4(假如分區一共有5條記錄)
row_number() over(partition by xxx order by yyy) //各分區按照yyy字段排序,即使yyy字段值一樣,rank的值也不一樣,從1一直往上加,如1、2、3、4、5
以上,partition by xxx 表示按照xxx字段分區(分區就是分組的意思),如果沒有partition by子句的話,所有的記錄當做一個分區。
2.聚合開窗函數:
sum(xxx) over(partition by yyy order by zzz)
count(1) over(partition by xxx order by yyy)
max(xxx) over(partition by yyy order by zzz)
min(xxx) over(partition by yyy order by zzz)
avg(xxx) over(partition by yyy order by zzz)
這5個聚合開窗函數用的時候再研究,粗略的看了一下各運行結果,跟平時的聚合函數有非常大的不同。
使用案例:
之前用group by分組時select的字段除了group by字段外,其他字段都要用聚合函數包起來(如果有的話),如count(1),sum(amount),max(created_date),這樣對其他非分組字段的處理只能滿足一些常規的需求,如分組查詢created_date最大的那條記錄
某紅包項目
需求一:查詢投保表中每個子紅包最近一次的投保失敗記錄
with r as ( select child_redpacket_id, max(updated_date) from red_packet_customerinfo where insure_status = -1 group by child_redpacket_id ) select rpc.child_redpacket_id, rpc.error_msg, rpc.updated_date from red_packet_customerinfo rpc where (rpc.child_redpacket_id, rpc.updated_date) in (select * from r) order by rpc.updated_date desc, rpc.child_redpacket_id
需求二:查詢投保表中每個子紅包最近兩次的投保失敗記錄
用group by 絞盡腦汁也想不出來怎么寫,但是用row_number() over(...) 相當簡單
row_number() over(partition by xxx order by yyy),按照xxx字段分組並且按照yyy字段排列,默認是升序排列,后面跟上desc則是降序排列
這樣每一條記錄都會增加一個row_number虛擬字段(可以重命名為任意字段),每一組row_number都是從1開始往上累計,且排序是按照yyy字段嚴格排序的。
這樣滿足需求二的sql就可以這樣寫:
with r as ( select rpc.*, row_number() over(partition by child_redpacket_id order by updated_date desc) from red_packet_customerinfo rpc where insure_status = -1 ) select r.child_redpacket_id, r.error_msg, r.updated_date from r where r.row_number <= 2 order by r.updated_date desc, child_redpacket_id