2016-10-04 4 views
2

У меня возникла проблема. Я не могу понять, как объединить последовательные строки диапазона дат вместе, основываясь на двух измерениях. Один хорошо для меня, но второй делает неприятностиКак объединить последовательный диапазон дат Oracle

Давайте представим таблицу в этой структуре с четырьмя возможными сценариями

emp_id | level | date_from | date_to  
-------------------------------------------------- 
    1  | A  | 7/31/2015 | 3/31/2016 
    1  | A  | 4/1/2016 | 1/1/3000 

    2  | A  | 7/31/2015 | 1/1/3000 

    3  | A  | 5/31/2015 | 12/31/2015 
    3  | B  | 1/1/2016 | 3/31/2016 
    3  | A  | 4/1/2016 | 6/30/2016 
    3  | B  | 7/1/2016 | 1/1/3000 

    4  | A  | 5/31/2015 | 12/31/2015 
    4  | A  | 1/1/2016 | 6/30/2016 
    4  | B  | 7/1/2016 | 1/1/3000 

Я хочу объединить только те строки, которые имеют последовательные диапазоны дат и act_level = prev_level

Я пытался сделать что-то вроде этого

SELECT emp_id 
, level 
, date_from 
, date_to 
-- 
, CASE 
    WHEN lag(level) over (partition by emp_id order by date_from) = level THEN 
     CASE 
      WHEN lag(date_to) over (partition by emp_id, level order by date_from) = date_from-1 
       THEN lag(date_from) over (partition by code_employee, level_name order by date_from) 
      ELSE NULL 
     END 
    ELSE 
     CASE 
      WHEN lag(level) over (partition by emp_id order by date_from) = level 
        OR 
        lead(level) over (partition by emp_id order by date_from) = level 
       THEN NULL 
      ELSE date_from 
     END 
    END date_from_new 
, date_to as date_to_new 
-- 
FROM src_table 
-- 
WHERE 1=1 

это дает мне почти RESU LTS, что я хочу:

emp_id | level | date_from | date_to | d_from_new | d_from_to 
-------------------------------------------------------------------------- 
    1  | A  | 7/31/2015 | 3/31/2016 |   | 3/31/2016 
    1  | A  | 4/1/2016 | 1/1/3000 | 7/31/2015 | 1/1/3000 

    2  | A  | 7/31/2015 | 1/1/3000 | 7/31/2015 | 1/1/3000 

    3  | A  | 5/31/2015 | 12/31/2015 | 5/31/2015 | 12/31/2015 
    3  | B  | 1/1/2016 | 3/31/2016 | 1/1/2016 | 3/31/2016 
    3  | A  | 4/1/2016 | 6/30/2016 | 4/1/2016 | 6/30/2016 
    3  | B  | 7/1/2016 | 1/1/3000 | 7/1/2016 | 1/1/3000 

    4  | A  | 5/31/2015 | 12/31/2015 |   | 12/31/2015 
    4  | A  | 1/1/2016 | 6/30/2016 | 5/31/2015 | 6/30/2016 
    4  | B  | 7/1/2016 | 1/1/3000 | 7/1/2016 | 1/1/3000 

Я просто фильтровать результат для d_from_new (date_from_new) не нулевые значения. Но я не уверен, что произойдет, если будет, например, 3x на том же уровне с последовательным диапазоном дат или 8 раз.

И если честно - мне не нравится запрос :)

У вас есть «чистые perfomence» и «глаза чистые» решения?

+0

Не уверен, что логика должна быть за 'act_level = prev_level', но посмотрите на [Упаковочное интервалы] (http://blogs.solidq.com/en/ sqlserver/интервалы упаковки /) Ицик Бен-Ган. Он написан для SQL Server, но Oracle поддерживает все аналитические функции, которые там используются. –

ответ

0

Пожалуйста, попробуйте этот запрос:

select emp_id, lvl, min(date_from) df, max(date_to) dt 
    from (
    select s2.*, rn - sum(marker) over (order by rn) as grp 
     from (
     select s1.*, 
       row_number() over (order by emp_id, date_from) rn, 
       case when lag(lvl) over (partition by emp_id order by date_from) 
         = lvl 
        and lag(date_to) over (partition by emp_id order by date_from) + 1 
         = date_from 
        then 1 
        else 0 
       end marker 
      from src_table s1) s2) 
    group by emp_id, lvl, grp 
    order by emp_id, min(date_from) 

В первом подзапроса S1 я добавил маркер, где 1 присваивается, если предыдущий уровень, соответствующий и даты подряд. Во втором подзапросе этот маркер используется для построения столбца GRP, который имеет одинаковые значения для всех совпадающих строк. Этот столбец используется в запросе окончательной группировки, чтобы найти минимум date_from и максимум date_to. Пожалуйста, запустите внутренние запросы отдельно, чтобы узнать, что происходит на каждом шаге. Протестировано, если имеется более двух последовательных строк.

Тестовые данные и выход:

create table src_table (emp_id number(6), lvl varchar2(2), date_from date, date_to date); 
insert into src_table values (1, 'A', date '2015-07-31', date '2016-03-31'); 
insert into src_table values (1, 'A', date '2016-04-01', date '3000-01-01'); 
insert into src_table values (2, 'A', date '2015-07-31', date '3000-01-01'); 
insert into src_table values (3, 'A', date '2015-05-31', date '2015-12-31'); 
insert into src_table values (3, 'B', date '2016-01-01', date '2016-03-31'); 
insert into src_table values (3, 'A', date '2016-04-01', date '2016-06-30'); 
insert into src_table values (3, 'B', date '2016-07-01', date '3000-01-01'); 
insert into src_table values (4, 'A', date '2015-05-31', date '2015-12-31'); 
insert into src_table values (4, 'A', date '2016-01-01', date '2016-06-30'); 
insert into src_table values (4, 'B', date '2016-07-01', date '3000-01-01'); 

EMP_ID LVL DF   DT 
------- --- ----------- ----------- 
     1 A 2015-07-31 3000-01-01 
     2 A 2015-07-31 3000-01-01 
     3 A 2015-05-31 2015-12-31 
     3 B 2016-01-01 2016-03-31 
     3 A 2016-04-01 2016-06-30 
     3 B 2016-07-01 3000-01-01 
     4 A 2015-05-31 2016-06-30 
     4 B 2016-07-01 3000-01-01 

8 rows selected 

 Смежные вопросы

  • Нет связанных вопросов^_^