Oracle中按ID分组获取最新日期行的SQL问题求助
如何获取每个ID对应的最新数据行?
先来看下你的测试数据:
测试表(test)数据
| id | from | to | value |
|---|---|---|---|
| 1 | 01.01.20 | 19.01.20 | 100 |
| 1 | 20.01.20 | 31.12.99 | 100 |
| 2 | 01.01.20 | 19.01.20 | 1001 |
| 2 | 25.01.20 | 31.12.99 | 1001 |
| 3 | 01.01.20 | 19.01.20 | 1002 |
| 3 | 29.01.20 | 31.12.99 | 1002 |
你的需求是拿到每个id对应的最新行(也就是每个id里from日期最大的那条记录),预期输出也很明确。
为什么你的SQL只返回一行?
你写的这条SQL:
select * from test where id in a AND from = (select max(from) from test where id in a);
有两个关键问题:
- 变量
a根本没定义,而且就算假设a是所有id的集合,你的子查询select max(from) from test where id in a会返回整个表中最大的from日期(也就是29.01.20),然后只筛选from等于这个日期的行,自然只会拿到id=3的那条数据。 - from是SQL的关键字,直接作为列名用很容易引发语法错误,最好用反引号(
`)把它包起来。
正确的解决方案
这里给你三种常用的实现方式,适配不同的数据库环境:
方法1:窗口函数(推荐,支持MySQL8.0+、PostgreSQL、SQL Server等)
用ROW_NUMBER()窗口函数按id分组,然后对每组内的from日期降序排序,取排序后第一行就是最新记录:
SELECT id, `from`, `to`, value FROM ( SELECT *, ROW_NUMBER() OVER(PARTITION BY id ORDER BY STR_TO_DATE(`from`, '%d.%m.%y') DESC) AS rn FROM test ) t WHERE rn = 1;
注:如果你的from列已经是日期类型,不需要STR_TO_DATE()转换,直接写ORDER BY from DESC就行。
方法2:关联子查询(适合不支持窗口函数的老版本数据库)
为每个id单独计算对应的最大from日期,再匹配原表数据:
SELECT t1.* FROM test t1 WHERE STR_TO_DATE(t1.`from`, '%d.%m.%y') = ( SELECT MAX(STR_TO_DATE(t2.`from`, '%d.%m.%y')) FROM test t2 WHERE t2.id = t1.id );
这个方法会逐行检查每个id的最大日期,确保每个id都能拿到对应的最新行。
方法3:GROUP BY + JOIN
先按id分组拿到每个id的最大from日期,再和原表关联获取完整行:
SELECT t1.* FROM test t1 JOIN ( SELECT id, MAX(STR_TO_DATE(`from`, '%d.%m.%y')) AS max_from FROM test GROUP BY id ) t2 ON t1.id = t2.id AND STR_TO_DATE(t1.`from`, '%d.%m.%y') = t2.max_from;
额外提醒
- 你的日期格式是
dd.mm.yy,要注意年份解析的问题(比如99会被识别为1999还是2099?不同数据库规则不同,得根据业务调整)。 - 尽量别用SQL关键字当列名,要是必须用,记得用反引号(MySQL)或者方括号(SQL Server)包裹。
内容的提问来源于stack exchange,提问作者A2N15
相关产品推荐
相关产品推荐

