總結幾種MySQL中常見的排名問題
前言:
在某些應用場景中,我們經常會遇到一些排名的問題,比如按成績或年齡排名。排名也有多種排名方式,如直接排名、分組排名,排名有間隔或排名無間隔等等,這篇文章將總結幾種MySQL中常見的排名問題。
創(chuàng)建測試表
create table scores_tb ( id int auto_increment primary key, xuehao int not null, score int not null ) ENGINE=InnoDB DEFAULT CHARSET=utf8; insert into scores_tb (xuehao,score) values (1001,89),(1002,99),(1003,96),(1004,96),(1005,92),(1006,90),(1007,90),(1008,94); # 查看下插入的數據 mysql> select * from scores_tb; +----+--------+-------+ | id | xuehao | score | +----+--------+-------+ | 1 | 1001 | 89 | | 2 | 1002 | 99 | | 3 | 1003 | 96 | | 4 | 1004 | 96 | | 5 | 1005 | 92 | | 6 | 1006 | 90 | | 7 | 1007 | 90 | | 8 | 1008 | 94 | +----+--------+-------+
1.普通排名
按分數高低直接排名,從1開始,往下排,類似于row number。下面我們給出查詢語句及排名結果。
# 查詢語句 SELECT xuehao, score, @curRank := @curRank + 1 AS rank FROM scores_tb, ( SELECT @curRank := 0 ) r ORDER BY score desc; # 排序結果 +--------+-------+------+ | xuehao | score | rank | +--------+-------+------+ | 1002 | 99 | 1 | | 1003 | 96 | 2 | | 1004 | 96 | 3 | | 1008 | 94 | 4 | | 1005 | 92 | 5 | | 1006 | 90 | 6 | | 1007 | 90 | 7 | | 1001 | 89 | 8 | +--------+-------+------+
上述查詢語句中,我們申明了一個變量 @curRank ,并將此變量初始化為0,查得一行將此變量加一,并以此作為排名。我們看到這類排名是沒間隔的并且有些分數相同但排名不同。
2.分數相同,名次相同,排名無間隔
# 查詢語句 SELECT xuehao, score, CASE WHEN @prevRank = score THEN @curRank WHEN @prevRank := score THEN @curRank := @curRank + 1 END AS rank FROM scores_tb, (SELECT @curRank :=0, @prevRank := NULL) r ORDER BY score desc; # 排名結果 +--------+-------+------+ | xuehao | score | rank | +--------+-------+------+ | 1002 | 99 | 1 | | 1003 | 96 | 2 | | 1004 | 96 | 2 | | 1008 | 94 | 3 | | 1005 | 92 | 4 | | 1006 | 90 | 5 | | 1007 | 90 | 5 | | 1001 | 89 | 6 | +--------+-------+------+
3.并列排名,排名有間隔
另外一種排名方式是相同的值排名相同,相同值的下一個名次應該是跳躍整數值,即排名有間隔。
# 查詢語句 SELECT xuehao, score, rank FROM (SELECT xuehao, score, @curRank := IF(@prevRank = score, @curRank, @incRank) AS rank, @incRank := @incRank + 1, @prevRank := score FROM scores_tb, ( SELECT @curRank :=0, @prevRank := NULL, @incRank := 1 ) r ORDER BY score desc) s; # 排名結果 +--------+-------+------+ | xuehao | score | rank | +--------+-------+------+ | 1002 | 99 | 1 | | 1003 | 96 | 2 | | 1004 | 96 | 2 | | 1008 | 94 | 4 | | 1005 | 92 | 5 | | 1006 | 90 | 6 | | 1007 | 90 | 6 | | 1001 | 89 | 8 | +--------+-------+------+
上面介紹了三種排名方式,實現起來還是比較復雜的。好在MySQL8.0增加了窗口函數,使用內置函數可以輕松實現上述排名。
MySQL8.0 利用窗口函數實現排名
MySQL8.0中可以利用 ROW_NUMBER(),DENSE_RANK(),RANK() 三個窗口函數實現上述三種排名,需要注意的一點是as后的別名,千萬不要與前面的函數名重名,否則會報錯,下面給出這三種函數實現排名的案例:
# 三條語句對于上面三種排名 select xuehao,score, ROW_NUMBER() OVER(order by score desc) as row_r from scores_tb; select xuehao,score, DENSE_RANK() OVER(order by score desc) as dense_r from scores_tb; select xuehao,score, RANK() over(order by score desc) as r from scores_tb; # 一條語句也可以查詢出不同排名 SELECT xuehao,score, ROW_NUMBER() OVER w AS 'row_r', DENSE_RANK() OVER w AS 'dense_r', RANK() OVER w AS 'r' FROM `scores_tb` WINDOW w AS (ORDER BY `score` desc); # 排名結果 +--------+-------+-------+---------+---+ | xuehao | score | row_r | dense_r | r | +--------+-------+-------+---------+---+ | 1002 | 99 | 1 | 1 | 1 | | 1003 | 96 | 2 | 2 | 2 | | 1004 | 96 | 3 | 2 | 2 | | 1008 | 94 | 4 | 3 | 4 | | 1005 | 92 | 5 | 4 | 5 | | 1006 | 90 | 6 | 5 | 6 | | 1007 | 90 | 7 | 5 | 6 | | 1001 | 89 | 8 | 6 | 8 | +--------+-------+-------+---------+---+
總結:
本文給出三種不同場景下實現統(tǒng)計排名的SQL,可以根據不同業(yè)務需求選取合適的排名方案。對比MySQL8.0,發(fā)現利用窗口函數可以更輕松實現排名,其實業(yè)務需求遠遠比我們舉的示例要復雜許多,用SQL實現此類業(yè)務需求還是需要慢慢積累的。
以上就是總結幾種MySQL中常見的排名問題的詳細內容,更多關于MySQL 排名的資料請關注腳本之家其它相關文章!
相關文章
mysql存儲過程 在動態(tài)SQL內獲取返回值的方法詳解
本篇文章是對mysql存儲過程在動態(tài)SQL內獲取返回值進行了詳細的分析介紹,需要的朋友參考下2013-06-06

