前言:

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

创建测试表

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 |
+--------+-------+-------+---------+---+

总结:

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

参考:

教你用SQL实现统计排名的更多相关文章

  1. 用sql语句写排名

    使用SQL语句求排名 表jh03有下列数据: name score aa 99 bb 56 cc 56 dd 77 ee 78 ff 76 gg 78 ff 50 1. 名次生成方式1 , Score ...

  2. SQL语句统计每天、每月、每年的 数据

    SQL语句统计每天.每月.每年的数据 1.每年select year(ordertime) 年,sum(Total) 销售合计from 订单表group by year(ordertime) 2.每月 ...

  3. 用SQL实现统计报表中的"小计"与"合计"的方法详解

    本篇文章是对使用SQL实现统计报表中的"小计"与"合计"的方法进行了详细的分析介绍,需要的朋友参考下   客户提出需求,针对某一列分组加上小计,合计汇总.网上找 ...

  4. SQL SERVER统计服务器所有的数据库(数据库文件)、表(表行数)、字段(各字段)等详细信息

    原文:SQL SERVER统计服务器所有的数据库(数据库文件).表(表行数).字段(各字段)等详细信息 USE STAT GO SET NOCOUNT ON IF EXISTS(SELECT 1 FR ...

  5. 全废话SQL Server统计信息(2)——统计信息基础

    接上文:http://blog.csdn.net/dba_huangzj/article/details/52835958 我想在大地上画满窗子,让所有习惯黑暗的眼睛都习惯光明--顾城<我是一个 ...

  6. 全废话SQL Server统计信息(1)——统计信息简介

    当心空无一物,它便无边无涯.树在.山在.大地在.岁月在.我在.你还要怎样更好的世界?--张晓风<我在> 为什么要写这个内容? 随着工作经历的积累,越来越感觉到,大量的关系型数据库的性能问题 ...

  7. 【转】SQL语句统计每天、每月、每年的数据

    原文:https://www.cnblogs.com/Fooo/p/3435687.html SQL语句统计每天.每月.每年的数据 1.每年select year(ordertime) 年,sum(T ...

  8. sql: T-SQL 统计计算(父子關係,樹形,分級分類的統計)

    ---sql: T-SQL 统计计算(父子關係,樹形,分級分類的統計) ---2014-08-26 塗聚文(Geovin Du) CREATE PROCEDURE proc_Select_BookKi ...

  9. 教你管理SQL实例系列(1-15)

    全系列转自:51CTO ->jimshu http://jimshu.blog.51cto.com 目录及原本连接如下: 教你管理SQL实例(1)数据库实例 教你管理SQL实例(2)服务启动帐户 ...

随机推荐

  1. 常用开发库 - MapStruct工具库详解

    常用开发库 - MapStruct工具库详解 MapStruct是一款非常实用Java工具,主要用于解决对象之间的拷贝问题,比如PO/DTO/VO/QueryParam之间的转换问题.区别于BeanU ...

  2. Hznu_oj 2340 你敢一个人过桥吗?

    Description 在漆黑的夜里,N位旅行者来到了一座狭窄而且没有护栏的桥边.如果不借助手电筒的话,大家是无论如何也不敢过桥去的.不幸的是,N个人一共只带了一只手电筒,而桥窄得只够让两个人同时过. ...

  3. Mybatis中由于${}直接注入引发的问题

    一.问题引入 我们先来看这段代码,我想从取值为${category}的表中查询全部信息. @Mapper public interface CategoryMapper { @Select(" ...

  4. java例题_35 找到最大值和最小值并交换位置

    1 /*35 [程序 35 最大最小交换] 2 题目:输入数组,最大的与第一个元素交换,最小的与最后一个元素交换,输出数组. 3 */ 4 5 /*分析 6 * 1.先初始化一个数组,然后从键盘获得值 ...

  5. Redis系列-存储篇sorted set主要操作命令

    Redis系列-存储篇sorted set主要操作函数小结 redis支持有序集合,即sorted set.sorted set在set的基础上,增加了排序属性,是set的升级版.这里简要谈谈sort ...

  6. [矩阵乘法]裴波拉契数列II

    [ 矩 阵 乘 法 ] 裴 波 拉 契 数 列 I I [矩阵乘法]裴波拉契数列II [矩阵乘法]裴波拉契数列II Description 形如 1 1 2 3 5 8 13 21 34 55 89 ...

  7. 13个精选的React JS框架

    如果你正在使用 React.js 或 React Native 创建用户界面,可以试一试本文推荐的这些框架. React.js 和 React Native 是流行的用户界面(UI)开发平台,且都是开 ...

  8. Recoil Input 光标位置被重置到末尾的问题

    考察如下代码,页面中有个输入框,通过 Recoil Atom 来存储输入的值. App.tsx function NameInput() { const [name, setName] = useRe ...

  9. vscode(Visual Studio Code)中安装Debugger for Chrome插件调试页面

    最近换了下编辑器,改用vscode(Visual Studio Code),很喜欢它左边显示的文件路径,轻松新建文件夹和文件,也喜欢它的编码转换功能,gbk和utf-8可以随时切换,因为公司网站有些页 ...

  10. 生活随笔:Furious 7:人生的路口,你先向西,但终点只有一个

       FOR PAUL It's never goodbye see you again         "他永远都是我们的家人."Dom起身准备离开 Letty问他,你打算不告而 ...