按日期范围根据值分组

Grouping based on value 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

谢谢!

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

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

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

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

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

在您上面的示例中,值 = 20000 的前三行恰好是整个集合的前三行,因此差异将为 0。然而,第四行值 = 20000 是数据集的第 9 行整个集合,所以现在差异是 5。您可以很容易地看到 20000 的值分为两组,因此,您可以通过在组中计算差异来分别找到每个组的 min/max 白天按条款。

N.B。这确实假设您的数据中的日期是连续的,或者如果有缺失日期,您假设缺失日期的值保持不变。如果您确实缺少天数,并且希望间隙中的值显示在不同的组中,则需要外连接到包含缺失日期的子查询。在那种情况下,我认为 GurV 的答案(带有我在评论中提到的 case 语句中的附加子句)将是最好的答案,因为这样可以避免外部连接到连续日期列表的需要。