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

当我们遇到一些需求,比如组内分组排序,分组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 单个分组的情况:

-- 按照学科分组求排名:
	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;

在这里插入图片描述

解释一下
第一次查询的时候,第一个@subject = NULL, 就会设置@row_number= 1,然后设置@subject = 数学,然后第二次查询的时候@subject与数学相等,然后执行@row_number= @row_number+ 1;如此类推。
所以,@subject和@row_number两个变量的顺序不能调换,否则会分组失败。

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

在这里插入图片描述


附上建表语句

建测试表

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);
  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MySQL 5.7版本中,没有内置的ROW_NUMBER函数的写法。如果你需要实现类似ROW_NUMBER功能,可以使用变量和子查询来实现。以下是一种实现方式: ```sql CREATE TABLE TZ_DIAG_STAND SELECT * FROM ( SELECT @RN := CASE WHEN @DIAGNOSIS_NAME = DIAGNOSIS_NAME THEN @RN + 1 ELSE 1 END AS RN, @DIAGNOSIS_NAME := DIAGNOSIS_NAME AS DIAG_NAME, MASTER_ID, NUM FROM ( SELECT T1.DIAGNOSIS_NAME, MASTER_ID, COUNT(1) NUM FROM ( SELECT MASTER_ID, DIAGNOSIS_NAME FROM ICD_10 WHERE MASTER_ID IS NOT NULL AND DIAGNOSIS_NAME = '妊娠合并肠炎' ) T1 GROUP BY T1.DIAGNOSIS_NAME, MASTER_ID ORDER BY DIAGNOSIS_NAME, NUM DESC ) A, (SELECT @RN := 0, @DIAGNOSIS_NAME := 0) B ) A WHERE RN = 1; ``` 这个查询使用了变量@RN和@DIAGNOSIS_NAME来模拟ROW_NUMBER函数的功能,并在最外层的WHERE子句中选择RN等于1的记录。这样就可以获得诊断编码出现最多的记录。请注意,这只是一种实现方式,具体的查询语句可能会根据实际情况有所调整。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [MySQL5.7版本没有row_number函数的写法](https://blog.csdn.net/qq_43278973/article/details/120205035)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值