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查询按日期对连续记录进行分组的主要内容,如果未能解决你的问题,请参考以下文章

按连续日期分组,忽略 SQL 中的周末

oracle 查询每组的最大值

如何在 Oracle SQL 上进行查询以获取时间间隔,按特定字段分组

是否可以按主键的一部分对 DQL 查询进行分组并返回具有 max() 日期时间记录(早于参考日期)的记录?

SQL 查询根据日期获取最新的 3 次发送,然后对记录进行分组

使用按日期分组的 sql 查询