Oracle SQL — нужна помощь в преобразовании одного значения даты EFF_DT в диапазон дат START_EFF_DT и END_EFF_DT с уникальными критериями

Я ударил стену с этим запросом, и я прошу любой помощи по этому вопросу.

Фон: Мне нужно создать запрос, который идентифицирует все «неоплачиваемые» рабочие дни на основе данных, доступных в нашей базе данных Oracle.

Наши данные отслеживания времени и труда содержат только 1 столбец даты (EFF_DT), представляющий «дату работы».

Упрощенная версия необработанной таблицы выглядит следующим образом:

EEIDWORK_DTКОД ОПЛАТЫ
111101.03.2022БЕЗ ОПЛАТЫ
111102.03.2022REG_WORK
111103.03.2022REG_WORK
111104.03.2022БЕЗ ОПЛАТЫ
111105.03.2022БЕЗ ОПЛАТЫ
111106.03.2022БОЛЬНОЙ
111107.03.2022БОЛЬНОЙ
111108.03.2022БЕЗ ОПЛАТЫ
111109.03.2022БЕЗ ОПЛАТЫ
111110.03.2022БЕЗ ОПЛАТЫ

Что мне нужно сделать, так это отфильтровать только строки «НЕОПЛАЧЕННЫЕ», а затем мне нужно определить «диапазон» дат начала/окончания работы неоплачиваемого отпуска.

Таким образом, ожидаемые результаты должны выглядеть следующим образом:

EEIDSTART_EFF_DTEND_EFF_DT
111101.03.202201.03.2022
111104.03.202205.03.2022
111108.03.202210.03.2022

Как мне подойти к разработке этого SQL для кристального отчета, который необходимо создать?

Любая помощь приветствуется!

Для фиксированного EEID даты ВСЕГДА представляют собой полную последовательность? Или могут быть пробелы - например, есть строки за 25 марта и 28 марта, но не за два дня между ними? И если могут быть пробелы, как с этим справиться? Если "НЕОПЛАЧЕНО" как 25 марта, так и 28 марта, и нет строк для дат между ними?

mathguy 21.03.2022 18:33

Это известно как проблема пробелов и островов. Смотрите соответствующий пост здесь: stackoverflow.com/questions/30803021/…

MilletSoftware 21.03.2022 19:07

@mathguy - между диапазоном дат определенно есть разрывы в датах (длинные выходные могут привести к такому разрыву дат). В этом сценарии, если код выплаты до и после разрыва является НЕОПЛАЧЕННЫМ, он по-прежнему считается последовательной строкой даты, т.е.: 24.03 - не оплачено 25.03 - не оплачено 28.03 - не оплачено 29.03 - не оплачено Отчет должен вывести: EEID: 1111; Start_Eff_Dt: 3/24; End_Eff_Dt 3/29

Tommy 21.03.2022 20:35
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
0
3
33
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

В Oracle 12.1 и более поздних версиях вы можете использовать match_recognize для самых разных задач сопоставления с образцом.

Данные испытаний:

create table time_labor (eeid number, work_dt date, paycode varchar2(10));

alter session set nls_date_format = 'yyyy/mm/dd';

insert into time_labor (eeid, work_dt, paycode)
    select 1111, to_date('2022/03/01'), 'UNPAID'   from dual union all
    select 1111, to_date('2022/03/02'), 'REG_WORK' from dual union all
    select 1111, to_date('2022/03/03'), 'REG_WORK' from dual union all
    select 1111, to_date('2022/03/04'), 'UNPAID'   from dual union all
    select 1111, to_date('2022/03/05'), 'UNPAID'   from dual union all
    select 1111, to_date('2022/03/06'), 'SICK'     from dual union all
    select 1111, to_date('2022/03/07'), 'SICK'     from dual union all
    select 1111, to_date('2022/03/08'), 'UNPAID'   from dual union all
    select 1111, to_date('2022/03/09'), 'UNPAID'   from dual union all
    select 1111, to_date('2022/03/10'), 'UNPAID'   from dual
;

commit;

Запрос и вывод:

select eeid, start_eff_dt, end_eff_dt
from   time_labor
match_recognize(
  partition by eeid
  order     by work_dt
  measures  first(work_dt) as start_eff_dt,
            last (work_dt) as   end_eff_dt
  pattern   ( unpaid+ )
  define    unpaid as paycode = 'UNPAID'
);

EEID  START_EFF_DT  END_EFF_DT
----  ------------  ------------
1111  2022/03/01    2022/03/01
1111  2022/03/04    2022/03/05
1111  2022/03/08    2022/03/10

Механизм match_recognize разделяет входные строки и упорядочивает их в каждом разделе в соответствии с предложениями partition by и order by. Он ищет совпадения шаблона unpaid+, что означает одну или несколько последовательных строк, классифицированных как unpaid, где эта классификация определена в предложении define. (Здесь unpaid — это просто мой выбор имени для этого классификатора; это кажется разумным выбором, но его можно назвать любым другим допустимым идентификатором, например x или abc_2902). match_recognize по умолчанию возвращает одну строку на совпадение с дополнительными вычисляемыми выражениями из предложения measures.

спасибо, что отправили меня в кроличью нору, чтобы узнать о match_recognize() и концепции проблем «промежутка и острова». Вчера я кое-что узнал, прочитав об этом. К сожалению, используемая нами база данных не является Oracle 12.1 :( Поэтому мне нужно будет найти другой метод для достижения желаемых результатов.

Tommy 22.03.2022 14:45

@Tommy - если ваша база данных такая старая (более чем на четыре версии отстает от текущей версии), вы должны четко указать это в своем вопросе. Какая является ваша версия? В разных версиях возможны разные решения. (Кроме того, я бы обновился как минимум до версии 12.1 даже только для match_recognize, который является исключительно мощным инструментом для решения многих проблем.)

mathguy 22.03.2022 15:17

У меня нет большого доступа к этой базе данных, она предоставлена ​​нашей третьей стороной, и у меня есть доступ только для чтения. Я подтвердил им сегодня, что он все еще на Oracle 11 .... Как бы ни был гладок предоставленный вами раствор, мне придется найти другой способ добиться этого :(

Tommy 23.03.2022 00:00

@Tommy - В Oracle 11.2 (и более ранних версиях) вы можете использовать очень хороший метод, известный как метод «фиксированных различий» или «табибито-сан», я опубликую отдельный ответ, чтобы показать, как это сделать.

mathguy 27.03.2022 22:04
Ответ принят как подходящий

Для пользователей более старых версий Oracle Database (до версии 12.1), которые не могут использовать предложение match_recognize, вот решение, использующее только аналитические функции и очень хороший метод выявления пробелов и островов, известный как «фиксированные различия» или «табибито». метод "сан". Хитрость заключается в создании дополнительных выражений группировки, помеченных grp, во вспомогательном подзапросе (который для простоты чтения я выделил в предложении with).

with
  prep as (
    select eeid, work_dt, paycode,
           row_number() over (partition by eeid          order by work_dt) 
         - row_number() over (partition by eeid, paycode order by work_dt) 
           as grp
    from   time_labor
  )
select eeid, min(work_dt) as start_eff_dt, max(work_dt) as end_eff_dt
from   prep
group  by eeid, paycode, grp
having paycode = 'UNPAID'
order  by eeid, start_eff_dt
;

Образцы данных (для тестирования) и результаты этого запроса можно найти в другом ответе, в котором используется match_recognize (только версии Oracle >= 12.1)

удивительно! спасибо @mathguy ... это SQL-решение - именно то, что я искал, чтобы завершить этот отчет

Tommy 29.03.2022 17:09

Другие вопросы по теме