SQL分组取最大值的方法

写这篇博文是为了帮助遇到同样问题的人,希望对你有用~

问题:求怎么查出同一课程id中时间最大的记录?(如下图所示)


1、刚开始想通过group by 分组课程id, 然后获取最大值,如下:

SELECT MAX(l.learn_time)
FROM learn l
where l.user_id = '14201109' 
GROUP BY l.course_id

查出来结果如下:


但是我想要查出来所有的字段,于是select后面加上 learn.*,嗯,应该没问题了,如下:

SELECT MAX(l.learn_time), l.*
FROM learn l
where l.user_id = '14201109' 
GROUP BY l.course_id

但查出来的结果出乎我的意料,你是不是也没想到,两列的时间字段竟然不一样!!!

由此想 MAX(l.learn_time)最大时间 应该是和 后面的learn.*记录没有直接关系的。


一开始是这样想的,通过时间逆排序,

select learn.*
from learn
where	learn.user_id = '14201109'
ORDER BY learn.learn_time DESC

然后在通过课程id分组应该就可以获取到了,但是排序order by必须放在分组group by 之后,像下面这样

select learn.*
from learn
where	learn.user_id = '14201109'
GROUP BY course_id
ORDER BY learn.learn_time DESC

结果发现learn_id 是1和6,通过group by分组之后它就只能取到的是这两条,这两条记录恰恰是时间最小的,而我们想要的是learn_id 为5和9的最大时间,经过这一番折磨,实在不知道怎么解决了,发了个求救信息,不一会儿,在同学的帮助下,就解决了只个问题,其实刚开始的思路是对的,就是先查到最大时间,再外边嵌套查询就好了,如下:

正确答案:

SELECT *
from learn
where learn.learn_time in (
			SELECT MAX(l.learn_time)
			FROM learn l
			where l.user_id = '14201109' 
			GROUP BY l.course_id
)

其实刚开始我也这样想过,但是我是把in写的等号“=”,结果一直报错说内嵌套只能查出来一条记录才可以,当时脑子短路,咋就没想到用in【/捂脸】【/捂脸】【/捂脸】,希望你们不要像我一样犯同样的错误。

突然想起来忘了说,我用的是mysql数据库


最后,大家如果发现我写的有错误的话,欢迎评论指出哦,共同进步。觉得我写的不错的,可以关注下哦^v^




### SQL Server 中按组获最大值方法SQL Server 中,为了按照特定条件分组并从中提每组的最大值,通常会结合 `GROUP BY` 和聚合函数如 `MAX()` 使用。当需求进一步复杂化到不仅限于简单的最大值计算,而是要获得与该最大值关联的一整行数据时,则可以采用更高级的技术手段实现这一目标。 #### 方法一:使用子查询配合 MAX 函数 对于简单场景下仅需得各组内的某个字段最大值的情况,可以直接利用 `GROUP BY` 结合 `MAX()` 来完成操作[^1]: ```sql SELECT CategoryID, MAX(UnitPrice) AS MaxUnitPrice FROM Products GROUP BY CategoryID; ``` 此段代码将返回每个类别 (`CategoryID`) 下最高的单价 (`MaxUnitPrice`)。 然而,如果目的是找出拥有最高单价的产品详情而不仅仅是数值本身,上述方法就显得不足了。这时可以通过嵌套子查询的方式达成目的[^4]: ```sql WITH RankedProducts AS ( SELECT p.*, ROW_NUMBER() OVER (PARTITION BY CategoryID ORDER BY UnitPrice DESC) as rn FROM Products p ) SELECT * FROM RankedProducts rp WHERE rp.rn = 1; ``` 这段脚本首先创建了一个名为 `RankedProducts` 的临时表(CTE),其中包含了所有产品信息以及它们在其所属类别的排名情况;接着在外层查询里只选那些排名第一即具有最高价格的商品记录。 #### 方法二:应用窗口函数 另一种更为优雅且性能优越的做法是运用窗口函数 `ROW_NUMBER()` 或者 `RANK()/DENSE_RANK()` 进行排序后再过滤出所需的结果集。这种方法允许一次性扫描整个表格的同时还能保持良好的可读性和维护性。 以上述例子为基础改进后的版本如下所示: ```sql SELECT * FROM ( SELECT *, ROW_NUMBER() OVER(PARTITION BY CategoryID ORDER BY UnitPrice DESC) AS RowNum FROM Products ) t WHERE t.RowNum = 1; ``` 这里同样先给每一类产品分配了一个基于其单价降序排列的位置编号(`RowNum`),最后一步则是挑选出这些序列号等于1的数据项作为最终输出。
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值