SQL数据分组后取最大值或者取前几个值(按照某一列排序)

本文介绍了一种使用SQL查询来获取按特定字段分组后的每组最新记录的方法。通过ROW_NUMBER()窗口函数配合子查询,可以高效地找出每个客户案例编号对应的最近支付时间。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今日做项目的时候,项目中遇到需要将数据分组后,分组中的最大值,想了想,不知道怎么做,于是网上查了查,终于找到了思路,经过比较这个查询时目前用时最快的,其实还有别的方法,但是我觉得我们只掌握最快的方法就行 ,好了,不说废话了!

直接上内容吧:以下数据是通过

SELECT [CustomerCaseNo],[PaymentsTime] FROM [BOMSDatabase].[dbo].[BAL_paymentsSwiftInfo] where StoresNo='zq00000034' group by CustomerCaseNo,[PaymentsTime] 

语句得到的,这个语句大家都会写了 



现在需要做的事,把这个数据按照[CustomerCaseNo]分组以后  取出PaymentsTime字段里面的最近时间,要做到这个,用下面的语句就可以实现

select * from( select StoresNo,[CustomerCaseNo],[PaymentsTime], ROW_NUMBER()  over(partition by CustomerCaseNo order by [PaymentsTime] desc) as rowNum
from BAL_paymentsSwiftInfo where StoresNo='zq00000034') ranked where ranked.rowNum <= 1 order by ranked.CustomerCaseNo, ranked.PaymentsTime desc
当执行完红字部分的SQL语句,就出现如下结果



达到我的要求,对数据分组以后,取出分组里面时间最近的数据记录,用到的SQL函数为
ROW_NUMBER()  over(partition by 分组字段order by 排序字段 desc)
<think>嗯,用户的问题很具体,是在MySQL里groupby时既要分组最大值又要拿到对应行的其他字段。这个问题其实挺典型的,尤其是做报表或者数据分析时经常遇到。用户引用了5个站内资料,看起来已经做过功课了。引用1提到基本groupby配合max的用法,引用2讲到any_value的解决方案,引用3和5都提到了嵌套查询技巧,引用4则指出mysql的宽松模式可能导致错误结果。用户显然注意到了不同解决方案的差异。用户的核心诉求其实是“数据对齐”——当到created最大值时,其他字段(比如用户id)必须严格属于同一条记录。这里有几个技术关键点:首先MySQL在ONLY_FULL_GROUP_BY关闭时的行为很危险,像引用4说的可能返回随机行;其次解决方案要兼顾准确性和性能。准备详细讲讲四种解决方案。第一种子查询关联最可靠但效率问题明显;第二种派生表在2018年测试时发现5万行数据要跑2秒多;窗口函数虽然优雅但版本要求高;any_value则是妥协方案。这些都需要结合用户的实际数据量来推荐。对了,用户没提MySQL版本,这点很重要。如果是5.7以下就只能选两种方案了。另外用户的应用场景也没说,如果是实时报表可能还要考虑索引优化。在回答最后需要用户补充这些信息。</think> 在MySQL中,**通过`GROUP BY`获分组最大值的同时返回其他非分组列的对应**,需使用子查询、连接或窗口函数,以确保数据严格对应。以下是4种方案及适用场景: --- ### 方法1:子查询关联(兼容性好) ```sql SELECT t.* FROM your_table t JOIN ( SELECT group_column, MAX(value_column) AS max_value FROM your_table GROUP BY group_column ) AS tmp ON t.group_column = tmp.group_column AND t.value_column = tmp.max_value; ``` * **原理**:先查出每组最大值,再关联原表获完整行 * **优点**:准确性强,兼容所有MySQL版本 * **缺点**:需多次扫描原表,大数据量时性能较低 * **示例**:获每个用户最新创建的数据 ```sql SELECT u.* FROM users u JOIN ( SELECT user_id, MAX(created) AS max_created FROM users GROUP BY user_id ) AS tmp ON u.user_id = tmp.user_id AND u.created = tmp.max_created; ``` --- ### 方法2:派生表 + LIMIT优化(特定场景高效) ```sql SELECT * FROM ( SELECT * FROM your_table ORDER BY value_column DESC LIMIT 1000000 -- 覆盖全表数据) AS sorted GROUP BY group_column; ``` * **原理**:先全表按目标列倒序排序,后分组第一条 * **优势**:避免多次关联,大数据量时可能更快 * **风险**:依赖MySQL宽松模式,**不满足SQL标准**(非分组列可能返回随机行) * **强制生效条件**:需关闭`ONLY_FULL_GROUP_BY`模式 ```sql SET SESSION sql_mode = ''; -- 临时关闭严格模式 ``` --- ### 方法3:窗口函数(MySQL 8.0+推荐) ```sql SELECT * FROM ( SELECT *, ROW_NUMBER() OVER ( PARTITION BY group_column ORDER BY value_column DESC ) AS rn FROM your_table ) AS ranked WHERE rn = 1; ``` * **原理**:为每组按排序生成行号,筛选组内第1行 * **优点**:执行效率高,语法清晰,符合标准 * **要求**:仅限**MySQL 8.0+**版本支持窗口函数 --- ### 方法4:ANY_VALUE()函数(快速近似解) ```sql SELECT group_column, MAX(value_column) AS max_value, ANY_VALUE(other_column) AS other_value -- 任意一个非分组 FROM your_table GROUP BY group_column; ``` * **原理**:使用`ANY_VALUE()`忽略非分组列的一致性校验 * **适用场景**:不需要精确匹配其他列(如仅展示辅助信息) * **风险**:返回的`other_column`**不保证属于最大值所在行** --- ### 关键陷阱提醒 1. **MySQL宽松模式隐患** 若未开启`ONLY_FULL_GROUP_BY`(默认关闭),直接写非分组列可能返回随机行(如引用4所述),导致业务逻辑错误: ```sql -- 错误示例:user_name可能来自非最大值行 SELECT user_id, MAX(created), user_name FROM orders GROUP BY user_id; ``` 2. **多最大值行处理** 当分组内存在多个相同最大值时,方法1、3会返回所有匹配行;方法2、4仅返回其中一行。 --- ### 最佳实践选择 | 场景 | 推荐方案 | |------|----------| | MySQL 8.0+ 精确匹配 | 窗口函数(方法3)✅ | | 旧版本MySQL 精确匹配 | 子查询关联(方法1)✅ | | 开发环境快速原型 | ANY_VALUE()(方法4)⚠️ | | 特定性能优化需求 | 派生表+LIMIT(方法2)⚠️(需严格测试) | > 务必通过`EXPLAIN`分析执行计划,对分组字段和排序字段建立索引可大幅提升性能[^1][^5]。 --- 相关问题: 1. 如何在MySQL 5.7中安全地关闭`ONLY_FULL_GROUP_BY`模式? 2. 当分组最大值对应多行时,如何返回所有记录? 3. 窗口函数方案中如何解决并列最大值问题? 4. 如何优化大数据量下的`GROUP BY`+`MAX()`查询性能?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值