SQL问题:如何按Id分组获取对应最大Date的完整记录?
嘿,这个问题我熟!我来给你拆解一下解决方案👇
问题分析与解决方案
1. 能不能直接在GROUP BY子句中带出对应最大Date的Name?
首先明确:不行。标准SQL的GROUP BY规则要求,SELECT里的非聚合字段必须要么出现在GROUP BY中,要么被聚合函数包裹。如果强行把Name加入GROUP BY,会按Id+Name分组,结果就不是每个Id只返回一条记录了——这显然不符合你的需求。
虽然有些数据库有非标准扩展(比如关闭MySQL的ONLY_FULL_GROUP_BY),但这种写法不通用,还可能返回不确定的结果,完全不推荐。
2. 三种实用解决方案
方法一:子查询+双字段内连接
你之前尝试连接但不会用双字段?其实很简单,连接条件同时匹配Id和Date(子查询得到的每个Id的最大日期),就能精准定位到对应行:
-- 替换your_table为你的实际表名 SELECT t.Id, t.Date, t.Name FROM your_table t INNER JOIN ( -- 先拿到每个Id的最大日期 SELECT Id, MAX(Date) AS max_date FROM your_table GROUP BY Id ) sub_query ON t.Id = sub_query.Id AND t.Date = sub_query.max_date;
这个方法兼容性拉满,几乎所有数据库都支持。
方法二:窗口函数(推荐)
如果你的数据库支持窗口函数(比如MySQL 8.0+、PostgreSQL、SQL Server、Oracle等),用ROW_NUMBER()会更简洁直观:
WITH ranked_records AS ( SELECT Id, Date, Name, -- 按Id分组,日期倒序排名,最大日期的行排名为1 ROW_NUMBER() OVER (PARTITION BY Id ORDER BY Date DESC) AS row_rank FROM your_table ) SELECT Id, Date, Name FROM ranked_records WHERE row_rank = 1;
- 如果存在同一个Id有多个相同最大日期的情况,
ROW_NUMBER()会随机选一条;如果想保留所有符合条件的行,把ROW_NUMBER()换成RANK()或DENSE_RANK()即可。 - 这种写法逻辑清晰,后期维护起来特别方便。
方法三:自连接筛选(适合旧版本MySQL)
如果是没有窗口函数的旧版本MySQL,可以用左自连接的方式筛选出最大日期的行:
SELECT t1.Id, t1.Date, t1.Name FROM your_table t1 LEFT JOIN your_table t2 ON t1.Id = t2.Id AND t1.Date < t2.Date -- 找同一个Id下日期更大的记录 WHERE t2.Id IS NULL; -- 找不到更大的日期,说明t1就是最新记录
总结
优先推荐窗口函数的写法,逻辑清晰易维护;如果需要兼容旧数据库,选择子查询连接或自连接的方法。
内容的提问来源于stack exchange,提问作者mikizas
相关产品推荐
相关产品推荐

