编写SQL查询获取每个ID的最新单条记录(支持指定ID)
没问题,这个需求在日常开发里挺常见的,我给你整理了几种实用的SQL写法,你可以根据自己使用的数据库来选择最合适的方案:
先确认下你的需求:从Employee表中(存在重复ID的情况),针对指定的ID(比如1和2),获取每个ID对应的最新时间的那条记录,最终返回对应ID各一条数据。先看看你提供的示例数据:
id time 1 04-04-18 06:46:55.191000000 PM 1 04-04-18 06:43:30.846000000 PM 1 04-04-18 06:38:30.968000000 PM 2 04-04-18 06:33:32.811000000 PM 2 04-04-18 06:28:32.337000000 PM 2 04-04-18 06:23:31.256000000 PM 3 04-04-...
方法1:使用窗口函数(最推荐,适配现代数据库)
如果你的数据库支持窗口函数(比如MySQL 8.0+、PostgreSQL、SQL Server、Oracle等),这是最简洁且不易出错的写法:
SELECT id, time FROM ( SELECT id, time, -- 按ID分组,每组内按时间倒序排序,给每条记录打序号 ROW_NUMBER() OVER (PARTITION BY id ORDER BY time DESC) AS row_num FROM Employee WHERE id IN (1, 2) -- 指定要查询的目标ID ) AS temp_table WHERE row_num = 1; -- 取每组的第一条,也就是最新时间的记录
说明:PARTITION BY id会把数据按ID分成独立的组,ORDER BY time DESC让每组内最新的时间排在最前面,row_num=1就精准定位到每组的最新记录。哪怕同一个ID有重复的最新时间,这个方法也只会返回一条(如果想返回所有重复的最新记录,可以把ROW_NUMBER()换成RANK())。
方法2:子查询+关联(兼容旧版数据库)
要是你的数据库不支持窗口函数(比如MySQL 5.x版本),可以用这种兼容性更强的写法:
SELECT e.id, e.time FROM Employee e INNER JOIN ( -- 先查出每个目标ID的最新时间 SELECT id, MAX(time) AS latest_time FROM Employee WHERE id IN (1, 2) GROUP BY id ) AS latest_records ON e.id = latest_records.id AND e.time = latest_records.latest_time;
说明:子查询先拿到每个ID的最大时间值,再通过ID和时间关联原表,就能得到对应的完整记录。需要注意的是,如果同一个ID存在多条时间完全相同的“最新记录”,这个写法会返回所有符合的记录,如果你能保证时间字段唯一,那这个方法非常好用。
方法3:用NOT EXISTS排除旧记录
还有一种更直观的思路:判断当前记录是不是该ID下时间最晚的——如果不存在同一个ID且时间比它晚的记录,那它就是我们要找的最新记录:
SELECT e1.id, e1.time FROM Employee e1 WHERE e1.id IN (1, 2) AND NOT EXISTS ( SELECT 1 FROM Employee e2 WHERE e2.id = e1.id AND e2.time > e1.time );
说明:这个写法不需要分组,逻辑简单易懂,但同样要注意时间重复的情况——如果有多个相同的最新时间,会返回所有对应的记录。
最后提个小建议:尽量把time字段存成datetime或timestamp类型,而不是字符串,这样排序和比较时间会更准确,避免字符串排序带来的问题。
内容的提问来源于stack exchange,提问作者Srikanth Hugar

