选择一个Id每天的最新记录 - Oracle pl sql
Posted
技术标签:
【中文标题】选择一个Id每天的最新记录 - Oracle pl sql【英文标题】:Select the latest record for an Id per day - Oracle pl sql 【发布时间】:2020-05-29 17:41:01 【问题描述】:我如何编写一个 sql 语句,它根据 Id 返回每天的最新记录。例如。数据如下。
Id Name Comment Value DateTime
1 Tim Test 100 02/06/2020 15:05:12
2 Sue House 200 03/06/2020 08:25:01
1 Tim Test 150 02/06/2020 18:05:12
3 Doug Cars 680 10/05/2019 04:45:10
2 Sue Tennis 200 03/06/2020 10:35:15
我会得到:
Id Name Comment Value DateTime
1 Tim Test 150 02/06/2020 18:05:12
3 Doug Cars 680 10/05/2019 04:45:10
2 Sue Tennis 200 03/06/2020 10:35:15
我是否需要按最大日期时间分组的子选择查询?
【问题讨论】:
(1) 您的 Oracle 版本是多少?视情况而定,有不同的答案。 (2) 为什么是plsql
标签? (3) 最重要的:能有关系吗?哪里有两行或多行具有相同的 ID 和相同的日期,具有完全相同的时间组件,都与该 goupr 中的“最新”相关联?如果是这样,应该如何处理?返回与该人和日期的“最新记录”相关的所有行?只返回其中一个,如果是,是哪一个? (或者“任何一个被捆绑的”都会同样好用吗?)
【参考方案1】:
我会采用窗口函数:
select id, name, comment, value, dateTime from
(
select id, name, comment, value, dateTime
, last_value(dateTime) over( partition by id, trunc(datetime)
order by dateTime
rows BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) lv
)
where dateTime=lv
【讨论】:
这不分组“每天,每个 ID” @WernfriedDomscheit;你是对的。窗口函数需要额外的 PARTITION BY trunc(DateTime)。我已经在上面编辑了我的答案。【参考方案2】:通过使用FIRST/LAST,您甚至不需要子查询:
WITH t(ID, NAME, COMMENT_, VALUE, DateTime) AS (
SELECT 1,'Tim','Test', 100, TO_DATE('02/06/2020 15:05:12', 'dd/mm/yyyy hh24:mi:ss') FROM dual
UNION ALL SELECT 2,'Sue','House', 200, TO_DATE('03/06/2020 08:25:01', 'dd/mm/yyyy hh24:mi:ss') FROM dual
UNION ALL SELECT 1,'Tim','Test', 150, TO_DATE('02/06/2020 18:05:12', 'dd/mm/yyyy hh24:mi:ss') FROM dual
UNION ALL SELECT 3,'Doug','Cars', 680, TO_DATE('10/05/2019 04:45:10', 'dd/mm/yyyy hh24:mi:ss') FROM dual
UNION ALL SELECT 2,'Sue','Tennis', 300, TO_DATE('03/06/2020 10:35:15', 'dd/mm/yyyy hh24:mi:ss') FROM dual
UNION ALL SELECT 2,'Sue','Steets', 400, TO_DATE('10/10/2020 10:35:15', 'dd/mm/yyyy hh24:mi:ss') FROM dual)
SELECT ID,
MAX(NAME) KEEP (DENSE_RANK LAST ORDER BY DateTime) AS NAME,
MAX(COMMENT_) KEEP (DENSE_RANK LAST ORDER BY DateTime) AS COMMENT_,
MAX(VALUE) KEEP (DENSE_RANK LAST ORDER BY DateTime) AS VALUE,
MAX(DateTime) KEEP (DENSE_RANK LAST ORDER BY DateTime) AS DateTime
FROM t
GROUP BY ID, TRUNC(DateTime);
+------------------------------------------+
|ID|NAME|COMMENT_|VALUE|DATETIME |
+------------------------------------------+
|1 |Tim |Test |150 |02.06.2020 18:05:12|
|2 |Sue |Tennis |300 |03.06.2020 10:35:15|
|2 |Sue |Steets |400 |10.10.2020 10:35:15|
|3 |Doug|Cars |680 |10.05.2019 04:45:10|
+------------------------------------------+
【讨论】:
【参考方案3】:一种简单的方法是使用相关子查询进行过滤:
select t.*
from mytable t
where t.datetime = (
select max(t1.datetime)
from mytable t1
where t1.datetime >= trunc(t.datetime)
and t1.datetime < trunc(t.datetime) + 1
)
你可能还喜欢反left join
的做法:
select t.*
from mytable t
left join mytable t1
on t1.datetime > t.datetime
and t1.datetime >= trunc(t.datetime)
and t1.datetime < trunc(t.datetime) + 1
where t1.id is null
【讨论】:
如果必须扫描表两次,这些方法的缺点。如果表很大,可能是性能问题 @BobC:无论哪种方式,您都需要多次扫描(分析功能在这方面并没有真正的不同)。 @GMB - 我不知道你为什么相信,但你肯定错了。 专门以改进为目标开发了分析函数。数据可能会被多次处理(内部查询、外部查询),但存储的数据只能从磁盘读取一次。 @gmb,对这两种解决方案运行一个解释计划,您将看到扫描次数。另外,我认为您的解决方案不会产生预期的结果;原始问题要求按 ID 对结果进行分组/分区。以上是关于选择一个Id每天的最新记录 - Oracle pl sql的主要内容,如果未能解决你的问题,请参考以下文章
Oracle PL/SQL:如何根据同一记录的 ID 字段返回字符串值?
Oracle PL/SQL 中自定义生成的 ID/序列? [复制]
Oracle PL/SQL:首先选择一组 id,然后循环/处理它们的方法