MySQL分类排名和分组TOP N实例详解

目录
  • 表结构
  • 题目一:获取每个科目下前五成绩排名(允许并列)
    • 分析:
  • 题目二:获取每个科目下最后两名学生的成绩平均值
    • 分析:
  • 题目三:获取每个科目下前五成绩排名(不允许并列)
  • 分析:
  • 总结

表结构

学生表如下:

CREATE TABLE `t_student` (
  `id` int NOT NULL AUTO_INCREMENT,
  `t_id` int DEFAULT NULL COMMENT '学科id',
  `score` int DEFAULT NULL COMMENT '分数',
  PRIMARY KEY (`id`)
);

数据如下:

题目一:获取每个科目下前五成绩排名(允许并列)

允许并列情况可能存在如4、5名成绩并列情况,会导致取前4名得出5条数据,取前5名也是5条数据。

SELECT
	s1.*
FROM
	student s1
	LEFT JOIN student s2 ON s1.t_id = s2.t_id
	AND s1.score < s2.score
GROUP BY
	s1.id
HAVING
	COUNT( s2.id ) < 5
ORDER BY
	s1.t_id,
	s1.score DESC

ps:取前4名时

分析:

1.自身左外连接,得到所有的左边值小于右边值的集合。以t_id=1时举例,24有5个成绩大于他的(74、64、54、44、34),是第6名,34只有4个成绩大于他的,是第5名......74没有大于他的,是第一名。

SELECT
	*
FROM
	student s1
	LEFT JOIN student s2 ON s1.t_id = s2.t_id
	AND s1.score < s2.score 

2. 把总结的规律转换成SQL表示出来,就是group by 每个student 的 id(s1.id),Having统计这个id下面有多少个比他大的值(s2.id)

SELECT
	s1.*
FROM
	student s1
	LEFT JOIN student s2 ON s1.t_id = s2.t_id
	AND s1.score < s2.score
GROUP BY
	s1.id
HAVING
	COUNT( s2.id ) < 5 

3. 最后根据 t_id 分类,score 倒序排序即可。

题目二:获取每个科目下最后两名学生的成绩平均值

取最后两名成绩

SELECT
	s1.*
FROM
	student s1
	LEFT JOIN student s2 ON s1.t_id = s2.t_id
	AND s1.score > s2.score
GROUP BY
	s1.id
HAVING
	COUNT( s1.id )< 2
ORDER BY
	s1.t_id,
	s1.score

并列存在情况下可能导致筛选出的同一t_id 下结果条数大于2条,但题目要求是取最后两名的平均值,多条平均后还是本身,故不必再对其处理,可以满足题目要求。

分组求平均值:

SELECT
	t_id,AVG(score)
FROM
	(
	SELECT
		s1.*
	FROM
		student s1
		LEFT JOIN student s2 ON s1.t_id = s2.t_id
		AND s1.score > s2.score
	GROUP BY
		s1.id
	HAVING
		COUNT( s1.id )< 2
	ORDER BY
		s1.t_id,
		s1.score
	) tt
GROUP BY
	t_id

结果:

分析:

1. 查询出所有t1.score>t2.score 的记录

SELECT
		s1.*,s2.*
	FROM
		student s1
		LEFT JOIN student s2 ON s1.t_id = s2.t_id
		AND s1.score > s2.score

2. group by s.id 去重,having 计数取2条

3. group by t_id 分别取各自学科的然后avg取均值

题目三:获取每个科目下前五成绩排名(不允许并列)

SELECT
	*
FROM
	(
	SELECT
		s1.*,
		@rownum := @rownum + 1 AS num_tmp,
		@incrnum :=
	CASE

			WHEN @rowtotal = s1.score THEN
			@incrnum
			WHEN @rowtotal := s1.score THEN
			@rownum
		END AS rownum
	FROM
		student s1
		LEFT JOIN student s2 ON s1.t_id = s2.t_id
		AND s1.score > s2.score,
		( SELECT @rownum := 0, @rowtotal := NULL, @incrnum := 0 ) AS it
	GROUP BY
		s1.id
	ORDER BY
		s1.t_id,
		s1.score DESC
	) tt
GROUP BY
	t_id,
	score,
	rownum
HAVING
	COUNT( rownum )< 5

分析:

1.引入辅助参数

SELECT
	s1.*,
	@rownum := @rownum + 1 AS num_tmp,
	@incrnum :=
CASE

		WHEN @rowtotal = s1.score THEN
		@incrnum
		WHEN @rowtotal := s1.score THEN
		@rownum
	END AS rownum
FROM
	student s1
	LEFT JOIN student s2 ON s1.t_id = s2.t_id
	AND s1.score > s2.score,
	( SELECT @rownum := 0, @rowtotal := NULL, @incrnum := 0 ) AS it

2.去除重复s1.id,分组排序

SELECT
		s1.*,
		@rownum := @rownum + 1 AS num_tmp,
		@incrnum :=
	CASE

			WHEN @rowtotal = s1.score THEN
			@incrnum
			WHEN @rowtotal := s1.score THEN
			@rownum
		END AS rownum
	FROM
		student s1
		LEFT JOIN student s2 ON s1.t_id = s2.t_id
		AND s1.score > s2.score,
		( SELECT @rownum := 0, @rowtotal := NULL, @incrnum := 0 ) AS it
	GROUP BY
		s1.id
	ORDER BY
		s1.t_id,
		s1.score DESC 

3.GROUP BY    t_id, score, rownum   然后 HAVING 取前5条不重复的

总结

到此这篇关于MySQL分类排名和分组TOP N实例详解的文章就介绍到这了,更多相关MySQL分类排名 TOP N内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Mysql教程分组排名实现示例详解

    目录 1.数据源 2.数据整体排名 1)普通排名 2)并列排名 3)并列排名 3.数据分组后组内排名 1)分组普通排名 2)分组后并列排名 3)分组后并列排名 4.分组后取各组的前两名 1.数据源 2.数据整体排名 1)普通排名 从1开始,按照顺序一次往下排(相同的值也是不同的排名). set @rank =0; select city , score, @rank := @rank+1 rank from cs order by score desc; 结果如下: 2)并列排名 相同的值是相同

  • 细数MySQL中SQL语句的分类

    1:数据定义语言(DDL)   用于创建.修改.和删除数据库内的数据结构,如:1:创建和删除数据库(CREATE DATABASE || DROP  DATABASE):2:创建.修改.重命名.删除表(CREATE  TABLE || ALTER TABLE|| RENAME TABLE||DROP  TABLE):3:创建和删除索引(CREATEINDEX  || DROP INDEX)   2:数据查询语言(DQL)   从数据库中的一个或多个表中查询数据(SELECT)   3:数据操作语

  • MySQL分类排名和分组TOP N实例详解

    目录 表结构 题目一:获取每个科目下前五成绩排名(允许并列) 分析: 题目二:获取每个科目下最后两名学生的成绩平均值 分析: 题目三:获取每个科目下前五成绩排名(不允许并列) 分析: 总结 表结构 学生表如下: CREATE TABLE `t_student` ( `id` int NOT NULL AUTO_INCREMENT, `t_id` int DEFAULT NULL COMMENT '学科id', `score` int DEFAULT NULL COMMENT '分数', PRIM

  • MySql批量插入优化Sql执行效率实例详解

    MySql批量插入优化Sql执行效率实例详解 itemcontractprice数量1万左右,每条itemcontractprice 插入5条日志. updateInsertSql.AppendFormat("UPDATE itemcontractprice AS p INNER JOIN foreigncurrency AS f ON p.ForeignCurrencyId = f.ContractPriceId SET p.RemainPrice = f.RemainPrice * {0},

  • mysql的存储过程、游标 、事务实例详解

    mysql的存储过程.游标 .事务实例详解 下面是自己曾经编写过的mysql数据库存储过程,留作存档,以后用到的时候拿来参考. 其中,涉及到了存储过程.游标(双层循环).事务. [说明]:代码中的注释只针对当时业务而言,无须理会. 代码如下: DELIMITER $$ DROP PROCEDURE IF EXISTS `transferEmailTempData`$$ CREATE PROCEDURE transferEmailTempData(IN jobId VARCHAR(24)) BEG

  • mysql alter table命令修改表结构实例详解

    mysql alter table语句可以修改表的基本结构,例如添加字段.删除字段.添加主键.添加索引.修改字段数据类型.对表重命名等等操作,本文章通过两个简单的实例向大家介绍mysql alter table的使用方法.  实例一:使用ALTER TABLE命令向表中添加字段.修改字段类型以及设置主键. 首先创建一个表,SQL语句如下: mysql> CREATE TABLE myTable( -> ID SMALLINT -> ); 使用desc命令查看表结构: mysql>

  • MySQL死锁问题分析及解决方法实例详解

    MySQL死锁问题是很多程序员在项目开发中常遇到的问题,现就MySQL死锁及解决方法详解如下: 1.MySQL常用存储引擎的锁机制 MyISAM和MEMORY采用表级锁(table-level locking) BDB采用页面锁(page-level locking)或表级锁,默认为页面锁 InnoDB支持行级锁(row-level locking)和表级锁,默认为行级锁 2.各种锁特点 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低 行级锁:开销大,加锁慢;

  • MySQL使用集合函数进行查询操作实例详解

    本文实例讲述了MySQL使用集合函数进行查询操作.分享给大家供大家参考,具体如下: COUNT函数 SELECT COUNT(*) AS cust_num from customers; SELECT COUNT(c_email) AS email_num FROM customers; SELECT o_num, COUNT(f_id) FROM orderitems GROUP BY o_num; SUM函数 SELECT SUM(quantity) AS items_total FROM

  • mysql存储过程之case语句用法实例详解

    本文实例讲述了mysql存储过程之case语句用法.分享给大家供大家参考,具体如下: 除了if语句,mysql提供了一个替代的条件语句CASE. mysql的 CASE语句使代码更加可读和高效.废话不多说,我们先来看下简单case语句的语法: CASE case_expression WHEN when_expression_1 THEN commands WHEN when_expression_2 THEN commands ... ELSE commands END CASE; 我们可以使

  • mysql存储过程之if语句用法实例详解

    本文实例讲述了mysql存储过程之if语句用法.分享给大家供大家参考,具体如下: mysql中的 IF语句允许我们根据表达式的某个条件或值结果来执行一组SQL语句,所以我们要在MySQL中形成一个表达式,可以结合文字,变量,运算符,甚至函数来组合.表达式可以返回TRUE,FALSE或NULL,这三个值之一.来看下语法结构: IF expression THEN statements; END IF; 如果上述表达式(expression)计算结果为TRUE,那么将执行statements语句,否

  • mysql外键的三种关系实例详解

    本文实例讲述了mysql外键的三种关系.分享给大家供大家参考,具体如下: 因为有foreign key的约束,使得两张表形成了三种了关系: 多对一 多对多 一对一 一对多或多对一 多对一 create table press( id int primary key auto_increment, name varchar(20) ); create table book( id int primary key auto_increment, name varchar(20), press_id

  • MySQL 的启动选项和系统变量实例详解

    本文实例讲述了MySQL 的启动选项和系统变量.分享给大家供大家参考,具体如下: MySQL的配置信息可以通过两种方式实现,一种是命令行形式,在启动MySQL服务时后边带上相关配置参数,此种方式会在MySQL重启后失效.另外一种是通过写入配置文件,如my.cnf,启动或者重启MySQL服务都会生效,此种方式是永久生效. 启动选项 命令行 在MySQL服务命令启动时,带上配置参数 启动方式可参考这篇:MySQL 的启动和连接方式 命令格式: 启动命令 --启动选项1[=值1] --启动选项2[=值

随机推荐