SQL:窗口函數處理分組與排序問題


一.窗口函數應用場景:

在日常工作中,經常遇到需要分部門排序的問題。比如:

  • 排名問題:每部門按照業績排名;
  • topN問題:找出每部門排名前N的員工。

當我們不了解“窗口函數”神奇的存在時,我們使用“晦澀難懂”的自連接SQL解決該問題。而窗口函數的存在為我們解決問題提供了方便。

二.窗口函數簡介:

MySQL從8.0開始支持窗口函數(OLAP函數),該功能在多數商業數據庫和部分開源數據庫中早已支持,用於快速解決SQL數據庫多維分析處理問題。

窗口函數的基本語法如下:

<窗口函數> over ( partition by <用於分組的列名>
                order by <用於排序的列名> )

 初學者經常混淆窗口函數與普通聚合函數的關系,二者區別如下:

  • 聚合函數:將多條記錄聚合為一條,窗口函數:每條記錄都會執行,有幾條記錄執行完還是幾條;
  • 聚合函數可以用於窗口函數中。

三.窗口函數的使用:

窗口函數種類繁多,我們這里只介紹序號函數——row_number( )/rank( )/dense_rank( )。

三者區別如下圖所示:

四.窗口函數的例子:

我們以leetcode面試題為例:

這是一道經典的topN問題,涉及先分組再排序,並且屬於dense_rank( )問題。

面對這種問題,解題步驟如下:

  1. 按給定列名分組(partiotion by 分組列名),並按給定列名排序(order by 排序列名),套入dense_rank窗口函數:    
select * ,
     dense_rank() over(partition by 分組列名
                       order by 排序列名 desc) as rk
from 表名;

 2. 篩選出topN,所以我們在上一步基礎上加入where語句篩選符合條件的數據:

select  *
from (
   select * , 
    row_number() over (
        partition by 分組列名
        order by 排序列名 desc) as rk
   from 表名) as a
where rk <= N;       

 針對leetcode第185題,我的題解如下:

select d.Name as Department, 
         e.Name as Employee, 
         e.Salary as Salary 
from (
   select *, 
          dense_rank() over (
                partition by DepartmentId
                order by Salary desc) as rk
   from Employee) e, Department d
where e.DepartmentId = d.Id and e.rk <= 3;        

 

 

 


免責聲明!

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



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