【精】MySQL5.7没有row_number()函数如何组内排序和求分组topN

news/2024/11/9 0:57:33/

当我们遇到一些需求,比如组内分组排序,分组topN等,很容易想到用row_number()函数
​在MySQL8.0版本中支持row_number函数,本文不做讨论,如果是MySQL5.7版本,要怎么写SQL呢?

测试表:
在这里插入图片描述
思路:

1.定义变量,用来存row_number

SET @row_number = 0;
SELECT*,( @row_number := @row_number + 1 ) AS ROW_NUMBER
from student
ORDER by score;

1.1 给每列数据标号

在这里插入图片描述

另一种简单优雅的写法是

SELECT*,( @row_number := @row_number + 1 ) AS ROW_NUMBER
from student,(select @row_number := 0) b
ORDER by score;

解释一下,因为sql执行顺序是 最先执行 FROM(可以参考sql执行顺序),所以会先初始化变量

2.组内排序

1.1 单个分组的情况:

-- 按照学科分组求排名:SELECTname,  subject, score,@row_number := IF( @subject = subject , @row_number + 1, 1 ) AS row_number , @subject := subject AS `分组字段`-- 用来分组的字段
FROMstudent,(select @row_number := 0) b
ORDER BYsubject,score DESC;

在这里插入图片描述

要注意的是,
查询条件中的@row_number语句一定要在@FIRST语句的前面。
因为第一次查询的时候,第一个@subject = NULL, 就会设置@row_number= 1,然后设置@subject = 数学,然后第二次查询的时候@subject与数学相等,然后执行@row_number= @row_number+ 1;如此类推。
如果顺序调换,@subject字段先赋值为数学,然后再判断@row_number:=IF(@subject = a.SUBJECT, @last + 1, 1 ) 的@subject= a.SUBJECT条件恒成立,
就会导致@row_number总是=@row_number+ 1。
最终的结果就导致组内分组排序失败。
不信你可以试试

2.2假如有多个分组字段:

比如这里,我要求同一门学科同一个学生的多次成绩排名

#求同一门学科同一个学生的多次成绩排名
SELECT a.name,  a.subject, a.score,  @row_number :=IF(@FIRST = a.name and @SECOND =a.subject, @row_number + 1, 1 ) AS rn,@FIRST := a.name as `分组字段1`, @SECOND :=a.subject as `分组字段2`
FROM student a, ( SELECT @row_number := 0, @FIRST := NULL,@SECOND := NULL ) b 
ORDER BY a.name, a.subject, a.score DESC

在这里插入图片描述

3.分组topN

有了以上内容,分组topN就好说了,只需要再在外面套一层,过滤一下

# 查询每门学科前三的学生:
SELECT * FROM(
SELECTname,  subject, score,@row_number := IF( @subject = subject , @row_number + 1, 1 ) AS row_number , @subject := subject AS `分组字段`  -- 用来分组的字段
FROMstudent,(select @row_number := 0) b
ORDER BYsubject,score DESC) twhere row_number<=3

在这里插入图片描述


附上建表语句

建测试表

CREATE TABLE `student` (`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键Id',`name` varchar(5) NOT NULL COMMENT '学生姓名',`subject` varchar(6) DEFAULT NULL COMMENT '科目',`score` smallint(3) DEFAULT NULL COMMENT '分数',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8;

插入数据

INSERT INTO `test`.`student`(`id`, `name`, `subject`, `score`) VALUES (1, '张三', '语文', 77);
INSERT INTO `test`.`student`(`id`, `name`, `subject`, `score`) VALUES (2, '李四', '语文', 67);
INSERT INTO `test`.`student`(`id`, `name`, `subject`, `score`) VALUES (3, '王五', '语文', 85);
INSERT INTO `test`.`student`(`id`, `name`, `subject`, `score`) VALUES (4, '张三', '数学', 82);
INSERT INTO `test`.`student`(`id`, `name`, `subject`, `score`) VALUES (5, '李四', '数学', 67);
INSERT INTO `test`.`student`(`id`, `name`, `subject`, `score`) VALUES (6, '王五', '英语', 85);
INSERT INTO `test`.`student`(`id`, `name`, `subject`, `score`) VALUES (7, '王五', '数学', 85);
INSERT INTO `test`.`student`(`id`, `name`, `subject`, `score`) VALUES (13, '张三', '语文', 87);
INSERT INTO `test`.`student`(`id`, `name`, `subject`, `score`) VALUES (14, '李四', '语文', 63);
INSERT INTO `test`.`student`(`id`, `name`, `subject`, `score`) VALUES (15, '王五', '语文', 55);
INSERT INTO `test`.`student`(`id`, `name`, `subject`, `score`) VALUES (16, '张三', '数学', 72);
INSERT INTO `test`.`student`(`id`, `name`, `subject`, `score`) VALUES (17, '李四', '数学', 97);
INSERT INTO `test`.`student`(`id`, `name`, `subject`, `score`) VALUES (18, '王五', '英语', 89);
INSERT INTO `test`.`student`(`id`, `name`, `subject`, `score`) VALUES (19, '王五', '数学', 87);

http://www.ppmy.cn/news/77110.html

相关文章

第四篇、基于Arduino uno,获取土壤湿度传感器的原始值和含水量——结果导向

0、结果 说明&#xff1a;先来看看串口调试助手显示的结果&#xff0c;第一个值是原始的模拟电压值&#xff0c;第二个值是含水量&#xff0c;如果是你想要的&#xff0c;可以接着往下看。 1、外观 说明&#xff1a;虽然土壤湿度传感器形态各异&#xff0c;但是原理和代码都是…

el-table如何实现筛选功能,以及filters,filter_method详解

在 ElementUI 的 el-table 组件中&#xff0c;提供了一个 el-table-column 组件的 filters 属性&#xff0c;可以用于对表格数据进行筛选操作。通过设置 filters 属性可以在表头中添加筛选菜单&#xff0c;用户可以通过选择菜单中的选项来过滤表格数据。 具体来说&#xff0c;可…

关于C语言的杂记5

文章目录 引入正文内部函数与外部函数相关数组的知识点数组的初始化测试一维数组在内存中存储的地址&#xff1a;遍历二维数组的值测试二维数组的地址(观察内存情况)数组下标为0开始的由来 两个数交换位置的三种方法 引入 写在前面&#xff1a;关于C语言这部分内容&#xff0c;…

[答疑]UML精粹里和你视频里说的不太一样

DDD领域驱动设计批评文集>> 《软件方法》强化自测题集>> 《软件方法》各章合集>> 第五元素 2023-4-14 20:32 这是是UML精粹里的。潘老师&#xff0c;这个跟你视频里讲的是不是不太一样&#xff1f;还是我理解错了&#xff1f; UMLChina潘加宇 这个&#…

CRM客户管理系统开发 获客管理营销全搞定

企业经营管理是有很大学问的&#xff0c;无论是生产经营、销售、服务还是客户管理、维护、营销都是需要付出一定的人力物力来管理的。传统的企业管理多是通过人工方式来完成&#xff0c;个中细节繁琐复杂&#xff0c;耗时耗力还很容易出现纰漏。所以随着科技的发展&#xff0c;…

QDir拼接路径解决各种斜杠问题

一般在项目中经常需要组合路径,与其他程序进行相互调用传递消息通信。 经常可能因为多加斜杠、少加斜杠等问题导致很多问题。 为了解决这些问题,我们可以使用QDir来完成路径的拼接,不直接拼接字符串。 QDir的静态方法QDir::cleanPath() 是为了规范化路径名的,在使用QDir组…

pthread多线程: 线程泄漏的检测

文章目录 1. 目的2. 什么是线程泄漏3. pthread 线程泄漏例子3.1 代码3.2 编译和运行3.3 简要分析 4. 检测线程泄漏4.1 编译链接时传入参数 -fsanitizethread4.2 确认 TSAN_OPTIONS 环境变量 5. 修复线程泄漏5.1 方法1&#xff1a; 主线程等待子线程5.2 方法2&#xff1a;子线程…

SSRF-服务器端请求伪造

漏洞定义和成因 SSRF(Server-Side Request Forgery:服务器端请求伪造) 是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。 一般情况下&#xff0c;SSRF攻击的目标是从外网无法访问的内部系统。&#xff08;正是因为它是由服务端发起的&#xff0c;所以它能够请求到与它…