Oracle sql查询按日期对连续记录进行分组
Posted
技术标签:
【中文标题】Oracle sql查询按日期对连续记录进行分组【英文标题】:Oracle sql query to group consecutive records by date 【发布时间】:2017-09-19 11:08:11 【问题描述】:使用以下示例数据,我正在尝试以相同的速率对记录进行分组。
id start_date end_date rate
-----------------------------------------------------------------
1 01/01/2017 12:00:00 am 01/01/2017 12:00:00 am 300
1 02/01/2017 12:00:00 am 02/01/2017 12:00:00 am 300
1 03/01/2017 12:00:00 am 03/01/2017 12:00:00 am 300
1 04/01/2017 12:00:00 am 04/01/2017 12:00:00 am 1000
1 05/01/2017 12:00:00 am 05/01/2017 12:00:00 am 500
1 06/01/2017 12:00:00 am 06/01/2017 12:00:00 am 500
1 07/01/2017 12:00:00 am 07/01/2017 12:00:00 am 1000
1 08/01/2017 12:00:00 am 08/01/2017 12:00:00 am 1000
1 09/01/2017 12:00:00 am 09/01/2017 12:00:00 am 300
我尝试过的:
select distinct id, mn_date, mx_date,rate
from (
select id, min(start_date) over (partition by grp order by start_date) mn_date,
max(end_date) over(partition by grp order by start_date desc) mx_date, rate
from (
select t.*, row_number() over(partition by id order by start_date) -row_number() over(partition by rate order by start_date)grp
from t
)
)
order by mn_date;
输出:
id mn_date mx_date rate
--------------------------------------------------------
1 01/01/2017 12:00:00 am 03/01/2017 12:00:00 am 300
1 04/01/2017 12:00:00 am 04/01/2017 12:00:00 am 1000
1 05/01/2017 12:00:00 am 06/01/2017 12:00:00 am 500
1 07/01/2017 12:00:00 am 09/01/2017 12:00:00 am 300
1 07/01/2017 12:00:00 am 09/01/2017 12:00:00 am 1000
期望的输出:
id mn_date mx_date rate
--------------------------------------------------------
1 01/01/2017 12:00:00 am 03/01/2017 12:00:00 am 300
1 04/01/2017 12:00:00 am 04/01/2017 12:00:00 am 1000
1 05/01/2017 12:00:00 am 06/01/2017 12:00:00 am 500
1 07/01/2017 12:00:00 am 08/01/2017 12:00:00 am 1000
1 09/01/2017 12:00:00 am 09/01/2017 12:00:00 am 300
按连续日期分组的最终结果:(感谢 Gordon)
select id, min(start_date), max(end_date), rate
from (
select id, start_date, end_date, rate, seqnum_i-seqnum_ir grp, sum(x) over(partition by id order by start_date) grp1
from (
select t.*,
row_number() over (partition by id order by start_date) as seqnum_i,
row_number() over (partition by id, rate order by start_date) as seqnum_ir,
case when LEAD(start_date) over (partition by id order by start_date)= end_date + 1
then 0
else 1
end x
from t
)
)
group by id, grp+grp1, rate
order by min(start_date);
【问题讨论】:
您想如何对数据进行分组?输出和期望输出有什么区别?你试过什么? 【参考方案1】:假设我们可以只使用start_date
来识别相邻记录(即没有间隙),那么您可以使用行号差异的方法:
select id, min(start_date) as mn_date, max(end_date) as mx_date, rate
from (select t.*,
row_number() over (partition by id order by start_date) as seqnum_i,
row_number() over (partition by id, rate order by start_date) as seqnum_ir
from t
) t
group by id (seqnum_i - seqnum_ir), rate;
要了解其工作原理,请查看子查询的结果。您应该能够“看到”两个行号的差异如何定义具有相同比率的相邻记录组。
【讨论】:
谢谢 Gordon:),我第一次尝试的查询也是基于您在另一个线程中的输入。感谢您的新解决方案。 如果我想将上述记录作为一个连续日期范围的组,您能否建议更改?假设我有一个额外的条目,其中现有列表的 start_date 和 end_date 分别为(11/01/2017 到 13/01/2017),速率为 300。查询应该导致新行,因为它不是连续的日期?我尝试过使用lead(),但未能获得预期的结果。还有一个条目(2017 年 1 月 1 日和 2017 年 1 月 15 日),评分 300。【参考方案2】:我发现最后一个值没有被正确分组,因为 X 的计算没有处理 NULL 返回,所以我把它改成这样:
,CASE
WHEN LEAD (start_date)
OVER (PARTITION BY id ORDER BY start_date)
IS NULL
THEN
0
WHEN LEAD (start_date)
OVER (PARTITION BY id ORDER BY start_date) =
end_date + 1
THEN
0
ELSE
1
END
x
【讨论】:
以上是关于Oracle sql查询按日期对连续记录进行分组的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Oracle SQL 上进行查询以获取时间间隔,按特定字段分组
是否可以按主键的一部分对 DQL 查询进行分组并返回具有 max() 日期时间记录(早于参考日期)的记录?