SQL实现按账号分组查询每组最后一行符合条件的记录
查询每个账号最新记录的SQL实现
问题说明
现有存储交易数据的表,结构及示例数据如下:
| ID | Account | Amount | Date |
|---|---|---|---|
| 1 | 4455 | 52 | 01-01-2022 |
| 2 | 4455 | 32 | 02-01-2022 |
| 3 | 4455 | 23 | 03-01-2022 |
| 4 | 4455 | 23 | 04-01-2022 |
| 5 | 6565 | 236 | 01-01-2022 |
| 6 | 6565 | 623 | 02-01-2022 |
| 7 | 6565 | 132 | 03-01-2022 |
| 8 | 2656 | 564 | 01-01-2022 |
| 9 | 2656 | 132 | 02-01-2022 |
需要检索每个账号对应的最后一行记录,期望输出结果如下:
| ID | Account | Amount | Date |
|---|---|---|---|
| 4 | 4455 | 23 | 04-01-2022 |
| 7 | 6565 | 132 | 03-01-2022 |
| 10 | 2656 | 13 | 03-01-2022 |
数据表总规模约2000条记录,以下提供两种通用SQL写法,执行效率完全满足该数据量级的使用需求。
可用SQL方案
方案1:窗口函数写法(推荐,逻辑清晰易维护)
适用于MySQL 8.0及以上、PostgreSQL、SQL Server等所有支持窗口函数的数据库环境。
核心逻辑是按账号分组,组内按记录新旧顺序倒序排列,取每组第一条即为对应账号的最新记录:
SELECT ID, Account, Amount, Date FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY Account ORDER BY Date DESC, ID DESC) AS row_rank FROM 替换为你的实际表名 ) tmp WHERE row_rank = 1;
说明:如果业务上明确同一个账号不会出现两条日期完全相同的记录,ORDER BY后可以去掉ID DESC,只保留Date DESC即可。
方案2:关联聚合写法(兼容性最好)
支持所有版本的SQL数据库,包括不支持窗口函数的旧版MySQL。
核心逻辑是先通过聚合计算出每个账号对应的最新记录标识,再关联原表取出完整字段:
SELECT t1.* FROM 替换为你的实际表名 t1 JOIN ( SELECT Account, MAX(Date) AS latest_date, MAX(ID) AS latest_id FROM 替换为你的实际表名 GROUP BY Account ) t2 ON t1.Account = t2.Account AND t1.Date = t2.latest_date AND t1.ID = t2.latest_id;
如果业务规则定义ID为自增主键、ID越大记录越新,可以直接简化写法,不需要关联日期字段:
SELECT t1.* FROM 替换为你的实际表名 t1 JOIN ( SELECT Account, MAX(ID) AS latest_id FROM 替换为你的实际表名 GROUP BY Account ) t2 ON t1.ID = t2.latest_id;
对于2000条数据的小表,以上两种写法执行耗时都在毫秒级,如果要进一步优化,给
Account字段加普通索引即可。
内容的提问来源于stack exchange,提问作者Bharath Kumar
相关产品推荐
相关产品推荐

