mysql 加序號以及成績單排名的幾種實現方式

首先   我們新建一個表,表信息如下:

CREATE TABLE `report` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
  `score` int(4) DEFAULT NULL COMMENT '分數',
  `user_name` varchar(255) DEFAULT NULL COMMENT '姓名',
  `exam_time` time DEFAULT NULL COMMENT '考試時間',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COMMENT='成績表';

假如是一般的排序 ,那我們直接按照分數降序排序,SELECT * FROM report ORDER BY score DESC;

查出來一個list,list的索引就當做它的排名(當然是索引+1)。

或者直接用sql,在sql裏標明排名序號:

SELECT
  @rownum := @rownum + 1 AS rownum,
  r.*
FROM
  report r,
  (SELECT @rownum := 0) b
ORDER BY
  score DESC

上面的@方式是mysql定義變量的方式,用:=進行賦值。

這兩種方法都是簡單的進行降序排序,然後加上序號,顯然很low,也不符合需求。

一般的成績單呢,應該是分數相同的,排名一致,以此類推。所以,我們給出三種查詢方式:

方式一:藉助建立僞表,比較大小並排序

SELECT
    count(b.user_name) + 1 AS rk,
    a.*
FROM
    report a
LEFT JOIN report b ON a.score < b.score
GROUP BY
    a.user_name
ORDER BY
    count(b.user_name) + 1;

方式二: 藉助於if函數判斷以及自定義方式

SELECT 
@rownum:=@rownum+1 AS rownum,
if(@score=A.score,@rank,@rank:=@rownum)as rank,
@score:=A.score,
A.user_name,A.score,A.exam_time
FROM
(SELECT * FROM report ORDER BY score DESC) A,
(SELECT @rank:=0,@rownum:=0,@score:=null)B 

方式三:藉助case when函數判斷:

select 
count(case when a.score < b.score then b.user_name else null end)+1 as rank,
a.user_name,a.score,a.exam_time
from report a 
left join report b 
on 1=1
group by a.user_name,a.score,a.exam_time
order by rank

  以上三種方式的結果大概意思是這樣:如下圖

  到此   成績單的排序,就基本滿足普通的需求了。

 

 

由於博主本人又遇到了新需求,對於一些小測驗啥的,要求,分數一樣的,按時間長短排序,分數時間都一樣,排名形同。

這樣的話,其實就是對以上三種方法再加些判斷條件。

對於第一種的話,就稍微複雜一點。如下:

方式A:

select a.rk+count(b.user_name) as rk,a.user_name,a.score,a.exam_time
from 
(
  select a.user_name,a.exam_time,a.score,count(b.user_name)+1 as rk
  from report a 
  left join report b on a.score < b.score 
  group by a.user_name
  order by count(b.user_name)+1
)a 
left join
(
  select a.user_name,a.exam_time,a.score,count(b.user_name)+1 as rk
  from report a 
  left join report b on a.score < b.score 
  group by a.user_name
  order by count(b.user_name)+1
)b 
on a.rk = b.rk 
and a.exam_time > b.exam_time
group by a.user_name
order by a.rk+count(b.user_name)

相當於是在第一種方式的基礎上,套了一大層當做表,然後再做判斷,當然對於第一種應該還有更優化的方法,歡迎大家來寫出自己的想法。結果如下圖:

這樣的寫法,乍一看,代碼有點多,那麼對於用函數的,怎麼查詢呢?

方式B:

SELECT 
@rownum:=@rownum+1 AS rownum,
if((@score=A.score && @exam_time=A.exam_time),@rank,@rank:=@rownum)as rank,
@score:=A.score,@exam_time:=A.exam_time,
A.user_name
FROM
(
SELECT * FROM report ORDER BY score DESC,exam_time ASC
) A,
(SELECT @rank:=0,@rownum:=0,@score:=NULL,@exam_time:=NULL)B

這個方法的結果如下圖:

 

那麼 ,假如想要查詢某個人的信息以及排名呢,所有人的都查出來了,查某個人的,就加個判斷條件啦

SELECT C.*
FROM
(
SELECT 
@rownum:=@rownum+1 AS rownum,
if(@score=A.score,@rank,@rank:=@rownum)as rank,
@score:=A.score,
A.user_name,A.score,A.exam_time
FROM
(SELECT * FROM report ORDER BY score DESC) A,
(SELECT @rank:=0,@rownum:=0,@score:=null)B 
) C WHERE C.user_name ='lisi'

以上。

歡迎大家評論,有更好的方法的話,大家可以相互交流下。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章