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

news/2024/7/24 10:10:39 标签: 数据库, sql, mysql

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

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

1.定义变量,用来存row_number

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

1.1 给每列数据标号

在这里插入图片描述

另一种简单优雅的写法是

sql">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 单个分组的情况:

sql">-- 按照学科分组求排名:
	SELECT
	name,  subject, score,
	@row_number := IF( @subject = subject , @row_number + 1, 1 ) AS row_number , 
	@subject := subject AS `分组字段`-- 用来分组的字段
FROM
	student,(select @row_number := 0) b
ORDER BY
	subject,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假如有多个分组字段:

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

sql">#求同一门学科同一个学生的多次成绩排名
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就好说了,只需要再在外面套一层,过滤一下

sql"># 查询每门学科前三的学生:
SELECT * FROM(
SELECT
	name,  subject, score,
	@row_number := IF( @subject = subject , @row_number + 1, 1 ) AS row_number , 
	@subject := subject AS `分组字段`  -- 用来分组的字段
FROM
	student,(select @row_number := 0) b
ORDER BY
	subject,score DESC) t
	where row_number<=3

在这里插入图片描述


附上建表语句

建测试表

sql">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;

插入数据

sql">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.niftyadmin.cn/n/355771.html

相关文章

Mybatis intercepter 扩展点生效原理

1、 MybatisSqlSessionFactoryBean 通过 setPlugins 添加插件 2、buildSqlSessionFactory() 给Configuration添加插件 if (!isEmpty(this.plugins)) {Stream.of(this.plugins).forEach(plugin -> {targetConfiguration.addInterceptor(plugin);LOGGER.debug(() -> &…

Flink用户自定义连接器(Table API Connectors)学习总结

文章目录 前言背景官网文档概述元数据解析器运行时的实现 自定义扩展点工厂类Source扩展Sink和编码与解码 自定义flink-http-connectorSQL示例具体代码pom依赖HttpTableFactoryHttpTableSourceHttpSourceFunctionHttpClientUtil 最后参考资料 前言 结合官网文档和自定义实现一…

【ChatgGPT】ChatgGPT生成Excel提取字符公式

参考视频&#xff1a;https://edu.csdn.net/learn/38346/613668 问题场景&#xff1a;网站用户发帖统计excel表中&#xff0c;C,D,E.F列有每个用户每周发布的文章数量&#xff0c;只有每周发布文章都至少2篇及以上的才有奖品。如何写excel公式来找出符合条件的人? 1.下载所需…

es 二、核心概念

目录 Nrt cluster集群概念 node节点 Document 文档 Index 索引 Field字段 Type 类型 shard分片 Replica shard副本 数据库和es概念对比 Nrt 写入一秒后就能搜到 cluster集群概念 一台机器启动一个实例即可&#xff0c;多个组成 node节点 一个实例一个节点 Documen…

AttributeError: module ‘gym‘ has no attribute ‘benchmark_spec‘解决办法

报错如下&#xff1a; 我安装的gym版本是gym-0.26.2 报错原因&#xff1a;gym版本太高了&#xff0c;需要降低版本 pip install gym0.9.0 -i https://pypi.douban.com/simple

机器学习基础(二)-具体分类模型【未完待续】

一、感知机 占坑 二、KNN kd树的搜索过程到底是怎么进行的&#xff1f; - 月来客栈的文章 - 知乎

JVM 问题整理

JVM内存模型 程序计数器:当前线程所执行的字节码的行号指示器,用于记录正在执行的虚拟机字节指令地址,线程私有。 虚拟机栈:存放基本数据类型、对象的引用、方法出口等,线程私有。 本地方法栈:和虚拟栈相似,只不过它服务于Native方法,线程私有 Java堆:java内存最大的一块,所有对…

【算法刷题】树和二叉树题型及方法归纳

1、树和二叉树的特点 &#xff08;1&#xff09;二叉树 二叉树是有左、右孩子的树&#xff0c;存储方式有顺序存储和链式存储。 二叉树的链式存储 struct TreeNode {int val;TreeNode *left;TreeNode *right;TreeNode() : val(0), left(nullptr), right(nullptr) {}TreeNod…