SQL实现group by 分组后组内排序

   在一个月黑风高的夜晚,本身无聊学习的SQL的时候,练习,突发奇想的想实现一个功能查询,一张成绩表有以下字段,班级ID,英语成绩,数据成绩,语文成绩以下图sql

实现 查询出 每一个班级英语成绩最高的前两名的记录。数据库

看起来不难的业务,作起来才知道还挺麻烦的,说白了其实就是实现分组后的组内排序,通常不思考的话咱们会写出这样的语句:函数

select top 2 English,Classid from CJ group by Classid order by English desc学习

出现这个错误,应该就明白了其实数据库的查询顺序是先分组的,最后才将结果进行排序。经过正常逻辑思考,经过班级分组,不就是分了三个组:班级1,班级2,班级3 。咱们能够经过聚合函数查询出,每一个组的个数,平均值等。但是你后面跟了英语成绩什么鬼?分组以后意味着,咱们不能查询单个的记录了,咱们查询的单位都是关于组的信息。spa

 

第一种实现 1code

SELECT * FROM CJ m
 where(
 select COUNT(*) from CJ n
     where m.Classid = n.Classid and n.English > m.English)<2
	 order by Classid, English desc

  也是当网上查的,能够这样理解,要找出前两名的成绩,只要符合比你成绩高的不超过2我的就好了。实际上是一个表的自链接,where条件就是一条一条记录对比,首先在m表中拿一条记录,是否符合 在同一班级中 比你成绩高的不超过2我的。这样就能够找到每一个班的前两名成绩。而后按照降序排列。blog

在这种实现中,也能够加上其余筛选条件 好比查询每一个班级女生中英语成绩前两名的记录排序

SELECT * FROM (select * from CJ where Gender='') m
 where(
 select COUNT(*) from (select * from CJ where Gender='') n
     where m.Classid = n.Classid and n.English > m.English)<2
     order by Classid, English desc


SELECT * FROM CJ m
 where(
 select COUNT(*) from CJ n
     where m.Classid = n.Classid and n.English > m.English and n.Gender='')<2   --指的是内表
and Gender=''  --指的是外表
     order by Classid, English desc

 

第二种是实现it

select a.Classid,a.English from
(select Classid,English,row_number() over(partition by Classid order by English desc) as n
from CJ) a
where n<=2

  最官方,最好的实现方式io

简单的说row_number()从1开始,为每一条分组记录返回一个数字

row_number() OVER (PARTITION BY COL1 ORDER BY COL2) 表示根据COL1分组,在分组内部根据 COL2排序,而此函数计算的值就表示每组内部排序后的顺序编号(组内连续的惟一的)

一样的加上条件

select a.Classid,a.English,n,test from
(select Classid,English,row_number() over(partition by Classid order by English desc) as n,123 test
from CJ where CJ.Gender='') a
where n<=2

能够看出先执行的是where 进行筛选后,再经过分组,组内再排序,排序后在添加编号,实际上是和正常的执行顺序同样的,只不过位置变了

相关文章
相关标签/搜索