根据日期范围的值进行分组

时间:2017-02-16 11:25:34

标签: oracle group-by date-range

您好我每天都有以下数据:

daytime        value
01.01.2017     20000
02.01.2017     20000
03.01.2017     20000
04.01.2017     35000
05.01.2017     35000
06.01.2017     40000
07.01.2017     40000
08.01.2017     50000

我如何拥有日期范围格式,如下图?

FromDate     ToDate      Value
01.01.2017   03.01.2017  20000
04.01.2017   05.01.2017  35000
06.01.2017   07.01.2017  40000
08.01.2017   08.01.2017  50000

谢谢!

2 个答案:

答案 0 :(得分:3)

Tabibitosan非常容易处理:

WITH your_table AS (SELECT to_date('01/01/2017', 'dd/mm/yyyy') daytime, 20000 VALUE FROM dual UNION ALL
                    SELECT to_date('02/01/2017', 'dd/mm/yyyy') daytime, 20000 VALUE FROM dual UNION ALL
                    SELECT to_date('03/01/2017', 'dd/mm/yyyy') daytime, 20000 VALUE FROM dual UNION ALL
                    SELECT to_date('04/01/2017', 'dd/mm/yyyy') daytime, 35000 VALUE FROM dual UNION ALL
                    SELECT to_date('05/01/2017', 'dd/mm/yyyy') daytime, 35000 VALUE FROM dual UNION ALL
                    SELECT to_date('06/01/2017', 'dd/mm/yyyy') daytime, 40000 VALUE FROM dual UNION ALL
                    SELECT to_date('07/01/2017', 'dd/mm/yyyy') daytime, 40000 VALUE FROM dual UNION ALL
                    SELECT to_date('08/01/2017', 'dd/mm/yyyy') daytime, 50000 VALUE FROM dual UNION ALL
                    SELECT to_date('09/01/2017', 'dd/mm/yyyy') daytime, 20000 VALUE FROM dual)
-- end of mimicking your table with data in it. See SQL below:
SELECT MIN(daytime) fromdate,
       MAX(daytime) todate,
       VALUE
FROM   (SELECT daytime,
               VALUE,
               row_number() OVER (ORDER BY daytime) - row_number() OVER (PARTITION BY VALUE ORDER BY daytime) grp
        FROM   your_table)
GROUP BY grp,
         VALUE
ORDER BY MIN(daytime);

FROMDATE   TODATE          VALUE
---------- ---------- ----------
01/01/2017 03/01/2017      20000
04/01/2017 05/01/2017      35000
06/01/2017 07/01/2017      40000
08/01/2017 08/01/2017      50000
09/01/2017 09/01/2017      20000

这样做是比较按日期排序的所有行的行号,然后是按日期排序的每个值的所有行的行号。如果值行在主数据集中是连续的,那么两组数据之间的差异保持不变,因此您可以按此分组。如果存在差距,则差异会增加。

在上面的示例中,value = 20000的前三行恰好是整个集合的前三行,因此差值为0.但是第四个值= 20000行是整个集合中的第9行,现在差异为5.您可以很容易地看到20000的值分为两组,因此,您可以通过在group by子句中包含差异计算来分别找到每个组的最小/最大日期时间。 / p>

N.B。这假设您的数据中的日期是连续的,或者如果缺少日期,您认为缺少日期的值保持不变。如果确实缺少了日期,并且希望跨越间隙的值显示在不同的组中,则需要外部联接到包含缺少日期的子查询。在这种情况下,我认为GurV的答案(我在评论中提到的案例陈述中的附加条款)将是最好的一个,因为这将避免外连接到连续列表的需要日期。

答案 1 :(得分:1)

如果我理解正确,您只想在连续日期相同的情况下对值进行分组。

您可以使用窗口函数根据值生成组并增加日期顺序,然后找到所需的聚合。

with your_table(daytime      ,value) as (
    select to_date('13.02.2017','dd.mm.yyyy'),25000 from dual union all
    select to_date('14.02.2017','dd.mm.yyyy'),20000 from dual union all
    select to_date('15.01.2017','dd.mm.yyyy'),90000 from dual union all
    select to_date('16.01.2017','dd.mm.yyyy'),90000 from dual union all
    select to_date('17.01.2017','dd.mm.yyyy'),95800 from dual union all
    select to_date('18.01.2017','dd.mm.yyyy'),95800 from dual union all
    select to_date('19.01.2017','dd.mm.yyyy'),95800 from dual union all
    select to_date('20.01.2017','dd.mm.yyyy'),95800 from dual union all
    select to_date('21.01.2017','dd.mm.yyyy'),95800 from dual union all
    select to_date('22.01.2017','dd.mm.yyyy'),95800 from dual union all
    select to_date('23.01.2017','dd.mm.yyyy'),95800 from dual union all
    select to_date('24.01.2017','dd.mm.yyyy'),90000 from dual union all
    select to_date('25.01.2017','dd.mm.yyyy'),90000 from dual union all
    select to_date('26.01.2017','dd.mm.yyyy'),90000 from dual 
)
select
    min(daytime) fromdate,
    max(daytime) todate,
    value
from (
    select
        t.*,
        sum(x) over (order by daytime) grp
    from (
        select 
            t.*,
            case when value = lag(value) over (order by daytime) 
            then 0 else 1 end x
        from your_table t
    ) t
) t group by grp, value
order by fromdate;

制作:

FROMDATE    TODATE      VALUE
15-JAN-17   16-JAN-17   90000
17-JAN-17   23-JAN-17   95800
24-JAN-17   26-JAN-17   90000
13-FEB-17   13-FEB-17   25000
14-FEB-17   14-FEB-17   20000