当前位置:Gxlcms > 数据库问题 > 教你用SQL实现统计排名

教你用SQL实现统计排名

时间:2021-07-01 10:21:17 帮助过:22人阅读

前言:?

在某些应用场景中,我们经常会遇到一些排名的问题,比如按成绩或年龄排名。排名也有多种排名方式,如直接排名、分组排名,排名有间隔或排名无间隔等等,这篇文章将总结几种MySQL中常见的排名问题。

创建测试表

  1. <code class="language-sql">create table scores_tb (
  2. id int auto_increment primary key,
  3. xuehao int not null,
  4. score int not null
  5. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  6. insert into scores_tb (xuehao,score) values (1001,89),(1002,99),(1003,96),(1004,96),(1005,92),(1006,90),(1007,90),(1008,94);
  7. # 查看下插入的数据
  8. mysql> select * from scores_tb;
  9. +----+--------+-------+
  10. | id | xuehao | score |
  11. +----+--------+-------+
  12. | 1 | 1001 | 89 |
  13. | 2 | 1002 | 99 |
  14. | 3 | 1003 | 96 |
  15. | 4 | 1004 | 96 |
  16. | 5 | 1005 | 92 |
  17. | 6 | 1006 | 90 |
  18. | 7 | 1007 | 90 |
  19. | 8 | 1008 | 94 |
  20. +----+--------+-------+</code>

1.普通排名

按分数高低直接排名,从1开始,往下排,类似于row number。下面我们给出查询语句及排名结果。

  1. <code class="language-sql"># 查询语句
  2. SELECT xuehao, score, @curRank := @curRank + 1 AS rank
  3. FROM scores_tb, (
  4. SELECT @curRank := 0
  5. ) r
  6. ORDER BY score desc;
  7. # 排序结果
  8. +--------+-------+------+
  9. | xuehao | score | rank |
  10. +--------+-------+------+
  11. | 1002 | 99 | 1 |
  12. | 1003 | 96 | 2 |
  13. | 1004 | 96 | 3 |
  14. | 1008 | 94 | 4 |
  15. | 1005 | 92 | 5 |
  16. | 1006 | 90 | 6 |
  17. | 1007 | 90 | 7 |
  18. | 1001 | 89 | 8 |
  19. +--------+-------+------+</code>

上述查询语句中,我们申明了一个变量 @curRank?,并将此变量初始化为0,查得一行将此变量加一,并以此作为排名。我们看到这类排名是没间隔的并且有些分数相同但排名不同。

2.分数相同,名次相同,排名无间隔

  1. <code class="language-sql"># 查询语句
  2. SELECT xuehao, score,
  3. CASE
  4. WHEN @prevRank = score THEN @curRank
  5. WHEN @prevRank := score THEN @curRank := @curRank + 1
  6. END AS rank
  7. FROM scores_tb,
  8. (SELECT @curRank :=0, @prevRank := NULL) r
  9. ORDER BY score desc;
  10. # 排名结果
  11. +--------+-------+------+
  12. | xuehao | score | rank |
  13. +--------+-------+------+
  14. | 1002 | 99 | 1 |
  15. | 1003 | 96 | 2 |
  16. | 1004 | 96 | 2 |
  17. | 1008 | 94 | 3 |
  18. | 1005 | 92 | 4 |
  19. | 1006 | 90 | 5 |
  20. | 1007 | 90 | 5 |
  21. | 1001 | 89 | 6 |
  22. +--------+-------+------+</code>

3.并列排名,排名有间隔

另外一种排名方式是相同的值排名相同,相同值的下一个名次应该是跳跃整数值,即排名有间隔。

  1. <code class="language-sql"># 查询语句
  2. SELECT xuehao, score, rank FROM
  3. (SELECT xuehao, score,
  4. @curRank := IF(@prevRank = score, @curRank, @incRank) AS rank,
  5. @incRank := @incRank + 1,
  6. @prevRank := score
  7. FROM scores_tb, (
  8. SELECT @curRank :=0, @prevRank := NULL, @incRank := 1
  9. ) r
  10. ORDER BY score desc) s;
  11. # 排名结果
  12. +--------+-------+------+
  13. | xuehao | score | rank |
  14. +--------+-------+------+
  15. | 1002 | 99 | 1 |
  16. | 1003 | 96 | 2 |
  17. | 1004 | 96 | 2 |
  18. | 1008 | 94 | 4 |
  19. | 1005 | 92 | 5 |
  20. | 1006 | 90 | 6 |
  21. | 1007 | 90 | 6 |
  22. | 1001 | 89 | 8 |
  23. +--------+-------+------+</code>

上面介绍了三种排名方式,实现起来还是比较复杂的。好在MySQL8.0增加了窗口函数,使用内置函数可以轻松实现上述排名。

MySQL8.0 利用窗口函数实现排名

MySQL8.0中可以利用?ROW_NUMBER(),DENSE_RANK(),RANK()?三个窗口函数实现上述三种排名,需要注意的一点是as后的别名,千万不要与前面的函数名重名,否则会报错,下面给出这三种函数实现排名的案例:

  1. <code class="language-sql"># 三条语句对于上面三种排名
  2. select xuehao,score, ROW_NUMBER() OVER(order by score desc) as row_r from scores_tb;
  3. select xuehao,score, DENSE_RANK() OVER(order by score desc) as dense_r from scores_tb;
  4. select xuehao,score, RANK() over(order by score desc) as r from scores_tb;
  5. # 一条语句也可以查询出不同排名
  6. SELECT xuehao,score,
  7. ROW_NUMBER() OVER w AS ‘row_r‘,
  8. DENSE_RANK() OVER w AS ‘dense_r‘,
  9. RANK() OVER w AS ‘r‘
  10. FROM `scores_tb`
  11. WINDOW w AS (ORDER BY `score` desc);
  12. # 排名结果
  13. +--------+-------+-------+---------+---+
  14. | xuehao | score | row_r | dense_r | r |
  15. +--------+-------+-------+---------+---+
  16. | 1002 | 99 | 1 | 1 | 1 |
  17. | 1003 | 96 | 2 | 2 | 2 |
  18. | 1004 | 96 | 3 | 2 | 2 |
  19. | 1008 | 94 | 4 | 3 | 4 |
  20. | 1005 | 92 | 5 | 4 | 5 |
  21. | 1006 | 90 | 6 | 5 | 6 |
  22. | 1007 | 90 | 7 | 5 | 6 |
  23. | 1001 | 89 | 8 | 6 | 8 |
  24. +--------+-------+-------+---------+---+</code>

总结:?

本文给出三种不同场景下实现统计排名的SQL,可以根据不同业务需求选取合适的排名方案。对比MySQL8.0,发现利用窗口函数可以更轻松实现排名,其实业务需求远远比我们举的示例要复杂许多,用SQL实现此类业务需求还是需要慢慢积累的。

参考:?

  • https://www.cnblogs.com/caicaizi/p/9803013.html
  • https://blog.csdn.net/sqsltr/article/details/94408487

技术图片

教你用SQL实现统计排名

标签:分数   tps   values   ica   ofo   总结   窗口函数   初始化   sel   

人气教程排行