MySQL:如何查詢出每個分組中的 top n 條記錄?


問題描述

需求:

查詢出每月 order_amount(訂單金額) 排行前3的記錄。

例如對於2019-02,查詢結果中就應該是這3條:

解決方法

MySQL 5.7 和 MySQL 8.0 有不同的處理方法。

1. MySQL 5.7

我們先寫一個查詢語句。

根據 order_date 中的年、月,和order_amount進行降序排列。

然后,添加一個新列:order_amount(本條記錄在本月中的名次)。

執行結果:

可以看到,根據年、月、訂單金額排序了,還多了一列order_rank,顯示出了本條記錄在本月的訂單金額排名情況。

上面SQL中比較個性的是這部分:

@current_month@order_rank 是我們自定義的變量。

使用 := 可以動態創建一個變量,而不需要使用 set 命令。

這句的含義:

取得order_date中的月份值,賦值給current_month,這樣就可以跟蹤每個月份。

這句的含義:

比較 current_month 和本條記錄中的月份,如果一樣,order_rank 自增1,否則,置為1

注意@current_month 是在 @order_rank 的后面,例如執行到這條記錄時:

if 判斷中,MONTH(order_date) 值為 2,而 current_month 值為 1,還是上條記錄設置的。

接下來,把上面的SQL語句作為一個子查詢,然后使用一個 where 條件就可以輕松拿到每組的 top 3。

最終語句:

執行結果:

2. MySQL 8

MySQL 8 引入了一個 rank() 函數,可以更簡便的實現排行的功能。

執行結果:

效果和 5.7 中的方法是一致的。

我們看下語句中的 rank() 方法:

  • PARTITION BY 是指定分區依據,這里是根據訂單的年、月進行分區。

  • ORDER BY 指定了分區內的排序依據,這里是根據訂單的 年、月、金額 進行降序排列。

這樣就會自動計算出排行數值。

需要注意的是,這個地方和 5.7 的方法不一樣:

就是參與排序的幾個值一樣的時候,rank 值是一樣的。

最終的SQL語句:

翻譯整理自:

https://towardsdatascience.com/mysql-how-to-write-a-query-that-returns-the-top-records-in-a-group-12865695f436

如果您有興趣實踐一下,在公眾號“性能與架構”中發送消息:200106,會回復實踐筆記的下載地址,包含建表語句、測試數據、MySQL5.7和8.0的這2個查詢語句。

推薦閱讀:


免責聲明!

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



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