2017-02-16 6 views
-1

Привет У меня есть данные в ежедневной основе ниже:Группировка на основе значения по диапазону дат

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 

Спасибо!

ответ

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 

Что это делает сравнение номер строки для всех строк упорядоченных по дате, а затем номер строки для всех строк для каждого значения, упорядоченного по дате. Если строки значений являются последовательными в основном наборе данных, то разница между двумя наборами данных остается неизменной, поэтому вы можете группировать ее. Если есть пробел, разница увеличивается.

В приведенном выше примере первые три строки для значения = 20000 являются первыми тремя строками всего набора, поэтому разница будет равна 0. Однако четвертое значение = 20000 строк является 9-й строкой в ​​целом поэтому разница теперь равна 5. Вы можете легко увидеть, что значение 20000 относится к двум группам, и как таковое вы можете найти минимальное/максимальное дневное время для каждой группы отдельно, включив этот разностный расчет в предложение group by.

N.B. Это предполагает, что даты в ваших данных являются последовательными или что если отсутствуют даты, которые вы считаете, значение остается неизменным для отсутствующих дат. Если у вас отсутствуют пропущенные дни, и вы хотите, чтобы значения в пробеле отображались в разных группах, вам необходимо выполнить внешнее соединение с подзапросом, который содержит отсутствующие даты. В этом случае я думаю, что ответ GurV (с дополнительным предложением в заявлении case, который я упомянул в комментариях) был бы лучшим, поскольку это позволит избежать необходимости внешнего соединения в списке последовательных дат.

+0

Бинго! Оно работает! Большое спасибо :) – akira

+0

Не знаете, как вы имеете в виду N.B. - возможно, вы имеете в виду, если в верхней части находятся десять строк, все с значением 20000, но даты - четыре последовательных дня, затем пробел, а затем еще шесть последовательных дней, и это должно производить две строки вместо одной ... Если это то, что вы имеете в виду, тогда незначительная модификация ** Tabibitosan ** может иметь дело с этим напрямую.Чтобы создать 'grp', используйте' daytime' непосредственно вместо первого 'row_number()'; таким образом, значения 'grp' будут представлять собой даты вместо чисел, но все это работает точно так же. – mathguy

+0

Хорошая точка, ta; Я никогда не думал об этом раньше! Будет играть с этим в понедельник * {:-) – Boneist

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 
+0

Привет, я вижу дублирующее значение с вашим решением, я покажу пример позже, спасибо! – akira

+0

@akirax, что вы имеете в виду, что вы видите дублирующиеся значения с помощью решения GurV? Похоже, что это работает для меня, когда я пытаюсь использовать некоторые тестовые данные. Это, безусловно, дает вывод, который вы вложили в свой ответ для введенных входных данных. – Boneist

+0

@akirax - Это действительно работает. Пожалуйста, см. Обновление – GurV