1. 程式人生 > >mysql給資料統計做排名

mysql給資料統計做排名

原文地址:https://my.oschina.net/u/2552765/blog/544052
1、問題描述


目前有一個表tb_rank(PlayerID,PlayerName,Score) PlayerID是Primary key(主鍵);

現在的需求是,希望在表tb_rank中再新增一列rankNum,這個rankNum記錄的是Score的排名

根據分數做降序排列)。



2、初步解決方法(不考慮Score相同的情況)


問題分析

    經過分析,我們可以將此問題大概分解為以下三個子問題:

(1) 在表tb_rank中增加一列rankNum;

ALTER TABLE tb_rank ADD rankNum INT;

(2)對錶tb_rank中的Score列進行降序排名,且將排名數值增加到被排序的元組中;

初次執行排序可以使用

SELECT PlayerID,PlayerName,Score,(@rank:=IFNULL(@rank,0)+1) rankNum 
FROM tb_rank 
ORDER  BY Score DESC

普遍使用的排序SQL為

SET @rank
:=0; SELECT PlayerID,PlayerName,Score,(@rank:[email protected]rank+1) rankNum  FROM tb_rank  ORDER  BY Score DESC

(3)用第2步的結果來更新新增列rankNum的值。

SET @rank:=0;

UPDATE tb_rank,(select PlayerID,( @rank:[email protected]rank+1) rankNum FROM
 tb_rank ORDER  BY score DESC) temp_tb_rank SET tb_rank.rankNum=temp_tb_rank.rankNum WHERE tb_rank.PlayerID=temp_tb_rank.PlayerID;


排名的tb_rank表查詢返回的結果為



    到此就實現了簡單的排名了。但是這裡存在一個問題,就是說當score相同的時候,

比如:

PlayerID是’12‘和’13‘以及’123456‘,它們的Score都是1000,

但是查詢出來的結果在排名上的呈現卻不一致。

    這個是不合理的。下面第3節介紹一種解決方法。


3、更進一步的解決方法


實現思路

    產生第二步中同樣的分數出現不同的排名的問題,其根因是排名實現沒有考慮分數相同的情況,

下面增加一個變數@preScore來儲存產生當前元組時,上一個元組的分數;然後在生成排名的列,

根據當前元組的分數與上一個元組的分數大小進行比較,如果相等,那麼排名不變,否則排名加1。

    編寫SQL語句需要注意一點,對變數@preScore的賦值需要放到排名列rankNum之後,

要讓其先生成排名,而後才可以更新@preScore變數。

從SQL語句的結果生成原理上看,SELECT語句中,寫在前面的列值是先生成,

寫在後面的列值是後得到的。例如,下面的SELECT語句中,

PlayerID的位置放在最前面,那麼實際返回查詢結果的時候,是先獲取PlayerID的值的。

<pre name="code" class="sql">SET @rank:=0;
SET @preScore:=0;


SELECT PlayerID,( IF( @preScore<>Score,@rank :[email protected]+1,@rank ) ) rankNum,@preScore:=Score FROM tb_rank ORDER BY score DESC



最後合成後的SQL語句為


SET @rank:=0;
SET @preScore:=0;

UPDATE tb_rank, (SELECT PlayerID,( IF( @preScore<>Score,@rank:[email protected]rank+1,@rank ) ) rankNum,@preScore:=Score  
FROM tb_rank 
ORDER  BY score DESC) temp_tb_rank
SET tb_rank.rankNum=temp_tb_rank.rankNum
WHERE tb_rank.PlayerID=temp_tb_rank.PlayerID;