Минимальная и максимальная дата до сбоя - PullRequest
0 голосов
/ 10 июля 2020

В Oracle у меня есть этот образец таблицы:

+------------+------------+------------+------------+
| EMPLOYEENO | DATE_FROM  |  DATE_TO   |   REASON   |
+------------+------------+------------+------------+
|        101 | 01/08/2019 | 31/08/2019 | SICK LEAVE |
|        101 | 01/09/2019 | 30/09/2019 | SICK LEAVE |
|        101 | 01/10/2019 | 31/10/2019 | SICK LEAVE |
|        101 | 01/11/2019 | 30/11/2019 | SICK LEAVE |
|        101 | 01/12/2019 | 31/12/2019 | SICK LEAVE |
|        101 | 01/01/2020 | 31/01/2020 | SICK LEAVE |
|        101 | 06/07/2020 | 12/07/2020 | SICK LEAVE |
+------------+------------+------------+------------+

Я бы хотел получить вот что:

+------------+------------+------------+------------+
| EMPLOYEENO | DATE_FROM  |  DATE_TO   |   REASON   |
+------------+------------+------------+------------+
|        101 | 01/08/2019 | 31/01/2020 | SICK LEAVE |
|        101 | 06/07/2020 | 12/07/2020 | SICK LEAVE |
+------------+------------+------------+------------+

HR присылает мне только больничные листы сотрудников месяц за месяцем, и я действительно не знаю, как суммировать эти даты, чтобы иметь только 1 запись для 1 «настоящего» отпуска по болезни, зная, что в течение двух месяцев не будет сбоев. Я читал о LAG (), но не смог найти способ выполнить эту работу.

Я не уверен, что «нарушение» в моем заголовке - лучший способ сформулировать это, поэтому, пожалуйста, не стесняйтесь отредактируйте его / помогите мне улучшить его.

Спасибо за ваше время.

Изменить: я работаю с Oracle 18 C

Ответы [ 2 ]

2 голосов
/ 10 июля 2020

Вы можете использовать функции lag и sum windows с GROUP BY следующим образом:

SQL> --SAMPLE DATA
SQL> WITH YOUR_TABLE( EMPLOYEENO , DATE_FROM  ,  DATE_TO   ,   REASON) AS
  2  (select 101 , TO_DATE('01/08/2019','DD/MM/YYYY') , TO_DATE('31/08/2019','DD/MM/YYYY') , 'SICK LEAVE' from dual union all
  3  select 101 , TO_DATE('01/09/2019','DD/MM/YYYY') , TO_DATE('30/09/2019','DD/MM/YYYY') , 'SICK LEAVE' from dual union all
  4  select 101 , TO_DATE('01/10/2019','DD/MM/YYYY') , TO_DATE('31/10/2019','DD/MM/YYYY') , 'SICK LEAVE' from dual union all
  5  select 101 , TO_DATE('01/11/2019','DD/MM/YYYY') , TO_DATE('30/11/2019','DD/MM/YYYY') , 'SICK LEAVE' from dual union all
  6  select 101 , TO_DATE('01/12/2019','DD/MM/YYYY') , TO_DATE('31/12/2019','DD/MM/YYYY') , 'SICK LEAVE' from dual union all
  7  select 101 , TO_DATE('01/01/2020','DD/MM/YYYY') , TO_DATE('31/01/2020','DD/MM/YYYY') , 'SICK LEAVE' from dual union all
  8  select 101 , TO_DATE('06/07/2020','DD/MM/YYYY') , TO_DATE('12/07/2020','DD/MM/YYYY') , 'SICK LEAVE' from dual)
  9  --YOUR QUERY STARTS FROM HERE
 10  select EMPLOYEENO, min(date_from) as date_from, max(date_to), REASON
 11  from
 12  (select t.*,
 13         sum(case when lg_dtto is null or lg_dtto <> date_from - 1 then 1 end)
 14             over (partition by EMPLOYEENO, REASON order by date_from) as sm
 15  from
 16  (select t.*,
 17         lag(date_to) over (partition by EMPLOYEENO, REASON order by date_from) as lg_dtto
 18    from your_table t) t
 19  )
 20  group by EMPLOYEENO, sm, REASON;

EMPLOYEENO DATE_FROM MAX(DATE_ REASON
---------- --------- --------- ----------
       101 01-AUG-19 31-JAN-20 SICK LEAVE
       101 06-JUL-20 12-JUL-20 SICK LEAVE

SQL>
1 голос
/ 10 июля 2020

Другой вариант для актуальных Oracle версий (12.1 и новее):

select *
from your_table
match_recognize (
   PARTITION BY employeeno,reason ORDER BY date_from
   MEASURES
     first(s.date_from) as date_from,
     last(b.date_to)    as date_to
   PATTERN (S B)
   DEFINE B as date_from=prev(date_to)+1
)

Полный тестовый пример:

with your_table( employeeno,date_from,date_to,reason) as( --test data:
 select 101 , TO_DATE('01/08/2019','DD/MM/YYYY') , TO_DATE('31/08/2019','DD/MM/YYYY') , 'SICK LEAVE' from dual union all
 select 101 , TO_DATE('01/09/2019','DD/MM/YYYY') , TO_DATE('30/09/2019','DD/MM/YYYY') , 'SICK LEAVE' from dual union all
 select 101 , TO_DATE('01/10/2019','DD/MM/YYYY') , TO_DATE('31/10/2019','DD/MM/YYYY') , 'SICK LEAVE' from dual union all
 select 101 , TO_DATE('01/11/2019','DD/MM/YYYY') , TO_DATE('30/11/2019','DD/MM/YYYY') , 'SICK LEAVE' from dual union all
 select 101 , TO_DATE('01/12/2019','DD/MM/YYYY') , TO_DATE('31/12/2019','DD/MM/YYYY') , 'SICK LEAVE' from dual union all
 select 101 , TO_DATE('01/01/2020','DD/MM/YYYY') , TO_DATE('31/01/2020','DD/MM/YYYY') , 'SICK LEAVE' from dual union all
 select 101 , TO_DATE('06/07/2020','DD/MM/YYYY') , TO_DATE('12/07/2020','DD/MM/YYYY') , 'SICK LEAVE' from dual
)
--main query:
select *
from your_table
match_recognize (
   PARTITION BY employeeno,reason ORDER BY date_from
   MEASURES
     first(s.date_from) as date_from,
     last(b.date_to)    as date_to
   PATTERN (S B)
   DEFINE B as date_from=prev(date_to)+1
)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...