SQL Запрос на выбор самой старой даты start_date, если в одном столбце нет изменений - PullRequest
0 голосов
/ 20 февраля 2020

У меня есть таблица со следующими столбцами per_all_assignments_m -

per_assignments

Person_id    position_id   system_person_type   start_date          END_DT     
1             1             EMP                01-JAN-2019        20-JAN-2019
1             1             EMP                21-JAN-2019        31-DEC-4712

2             1             EMP                01-JAN-2019        03-JUL-2019
2             1             EMP                04-JUL-2019        08-SEP-2019
2             2             EMP                09-SEP-2019        31-DEC-2019 
2             2             EMP                01-JAN-2020        31-DEC-4712

3             10             EMP                01-JAN-2019        20-JAN-2019  
3             10             EMP                21-JAN-2019        08-SEP-2019
3             10             EMP                09-SEP-2019       20-JAN-2020
3             10             EMP                21-JAN-2020       31-DEC-4712

Я создал приведенный ниже запрос для извлечения, если есть изменение значения в столбце position_id , Этот запрос будет извлекать дату, когда дата была изменена, и предыдущую дату начала.

select person_id, prev_start_dt, effective_start_date current_start_dt,
       case pos_new when pos_old then 1 else pos_old end pos_old
  from (
    select person_id, position_id pos_new, effective_start_date, effective_end_date,
               lag(position_id) over (partition by person_id order by effective_start_date) pos_old,
               lag(effective_start_date) over (partition by person_id order by effective_start_date) prev_start_dt, 
               case effective_start_date when 1 + lag(effective_end_date) over (partition by person_id order by effective_start_date) 
                             then 1 end flag
          from per_all_assignments_m
          where person_id=1
and assignment_type = 'E')
  where flag = 1 and (pos_new <> pos_old )

Для приведенной выше таблицы этот запрос будет вызывать 09-SEP-2019 для сотрудника № 2 в качестве current_start_dt и 04-JUL-2019 в качестве prev_start_dt

Question -

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

Пример - для EE # 1, current_start_dt должно быть 01- JAN-2019 и prev_start_dt должны быть одинаковыми для EE # 3, current_start_dt и prev_start_dt должны быть 01-JAN-2019.

Любые предложения будут очень полезны!

Требуемый вывод -

 Person_id            prev_start_dt                 current_start_dt                 pos_old
 1                      01-JAN-2019                    01-JAN-2019                    1
 2                       04-JUL-2019                   09-SEP-2019                    1
 3                       01-JAN-2019                   01-JAN-2019                    10

Ответы [ 2 ]

0 голосов
/ 20 февраля 2020

Вот один из способов сделать это:

cte2 getr person_id с изменениями, результатом будет строка person_id и добавление первого вхождения person_id без изменений

Fiddle

    with cte as
    (                     
  select 1     as Person_id,        1     as position_id,        'EMP'      as system_person_type,          STR_TO_DATE('01-JAN-2019', "%d-%M-%Y")  as start_date,     STR_TO_DATE('20-JAN-2019', "%d-%M-%Y") as END_DT
union select 1,             1 ,            'EMP' ,               STR_TO_DATE('21-JAN-2019', "%d-%M-%Y"),        STR_TO_DATE('31-DEC-4712', "%d-%M-%Y")
union select 2 ,            1  ,           'EMP'  ,              STR_TO_DATE('01-JAN-2019', "%d-%M-%Y") ,       STR_TO_DATE('03-JUL-2019', "%d-%M-%Y")
union select 2  ,           1   ,          'EMP'   ,             STR_TO_DATE('04-JUL-2019', "%d-%M-%Y")  ,      STR_TO_DATE('08-SEP-2019', "%d-%M-%Y")
union select 2   ,          2    ,         'EMP'    ,            STR_TO_DATE('09-SEP-2019', "%d-%M-%Y")   ,     STR_TO_DATE('31-DEC-2019' , "%d-%M-%Y")
union select 2    ,         2     ,        'EMP'     ,           STR_TO_DATE('01-JAN-2020', "%d-%M-%Y")    ,    STR_TO_DATE('31-DEC-4712', "%d-%M-%Y")
union select 3     ,        10     ,        'EMP'     ,           STR_TO_DATE('01-JAN-2019', "%d-%M-%Y")    ,    STR_TO_DATE('20-JAN-2019'  , "%d-%M-%Y")
union select 3      ,       10      ,       'EMP'      ,          STR_TO_DATE('21-JAN-2019', "%d-%M-%Y")     ,   STR_TO_DATE('08-SEP-2019', "%d-%M-%Y")
union select 3       ,      10       ,      'EMP'       ,         STR_TO_DATE('09-SEP-2019', "%d-%M-%Y")      , STR_TO_DATE('20-JAN-2020', "%d-%M-%Y")
union select 3        ,     10        ,     'EMP'        ,        STR_TO_DATE('21-JAN-2020', "%d-%M-%Y")       ,STR_TO_DATE('31-DEC-4712', "%d-%M-%Y");

    ),
    cte2 as 
    (
    select a.Person_id,  ( (b.start_date)) as prev_start_dt,  (a.start_date) as current_start_dt, (b.position_id) 
    from cte a left join cte b on a.Person_id = b.Person_id and a.start_date >  b.start_date and a.position_id <> b.position_id
    and not exists(select 1 from cte c where a.Person_id = c.Person_id and a.start_date >  c.start_date and c.start_date >  b.start_date)
    )
    select Person_id, prev_start_dt, current_start_dt, position_id from cte2 where position_id is not null
    union
    select a.Person_id, a.start_date, a.start_date, a.position_id from cte a where not exists(select 1 from cte b where a.Person_id = b.Person_id and a.start_date > b.start_date)
    and a.Person_id not in (select Person_id from cte2 where position_id is not null)


Output:

    Person_id   prev_start_dt   current_start_dt    position_id
    1            2019-01-01        2019-01-01        1
    2            2019-07-04        2019-09-09        1
    3            2019-01-01        2019-01-01        10
0 голосов
/ 20 февраля 2020

Если вы хотите отслеживать все случаи, когда происходит изменение идентификатора позиции, должно работать что-то вроде ниже:

with cte as
(                     
       select 1 as Person_id,1 as position_id,'EMP' as system_person_type,cast('01Jan2019' as date) as Start_date,cast('20Jan2019' as date) as end_dt from dual union
        select 1 as Person_id,1 as position_id,'EMP' as system_person_type,cast('21Jan2019' as date) as Start_date,cast('31Dec4712' as date) as end_dt from dual union
        select 2 as Person_id,1 as position_id,'EMP' as system_person_type,cast('01Jan2019' as date) as Start_date,cast('03Jul2019' as date) as end_dt from dual union
        select 2 as Person_id,1 as position_id,'EMP' as system_person_type,cast('04Jul2019' as date) as Start_date,cast('08Sep2019' as date) as end_dt from dual union
        select 2 as Person_id,2 as position_id,'EMP' as system_person_type,cast('09Sep2019' as date) as Start_date,cast('31Dec2019' as date) as end_dt from dual union
        select 2 as Person_id,2 as position_id,'EMP' as system_person_type,cast('01Jan2020' as date) as Start_date,cast('31Dec4712' as date) as end_dt from dual union
        select 3 as Person_id,10 as position_id,'EMP' as system_person_type,cast('01Jan2019' as date) as Start_date,cast('20Jan2019' as date) as end_dt from dual union
        select 3 as Person_id,10 as position_id,'EMP' as system_person_type,cast('21Jan2019' as date) as Start_date,cast('08Sep2019' as date) as end_dt from dual union
        select 3 as Person_id,10 as position_id,'EMP' as system_person_type,cast('09Sep2019' as date) as Start_date,cast('20Jan2020' as date) as end_dt from dual union
        select 3 as Person_id,10 as position_id,'EMP' as system_person_type,cast('21Jan2020' as date) as Start_date,cast('31Dec4712' as date) as end_dt from dual
)

select x.Person_Id,
      COALESCE(x.lag_start,x.min_date) as Prev_start_dt,
      x.min_date as Current_Start_Dt,
      COALESCE(x.lag_pos,x.position_id) as Pos_old
FROM
  (select person_id, 
        position_id,       
        min(start_date) as min_date, 
        max(start_date) as max_date, 
        lag(max(start_date)) Over(Partition by Person_Id Order by max(start_date)) as lag_start,
        lag(position_id) Over(Partition by Person_Id Order by min(start_date)) as lag_pos
  from cte
  group by person_id, position_id) x
inner join
  (select person_id,
          count(distinct position_id) as cnt
  from cte
  group by person_id) y
ON x.person_id=y.person_id
Where x.Position_id<>x.lag_pos or y.cnt=1

Идея состоит в том, чтобы сгруппировать информацию на уровне человека и позиции, а затем используйте функцию задержки, чтобы определить, есть ли изменение. Фильтр Cnt = 1 применяется для получения случаев, когда нет изменения позиции. Надеюсь, это поможет.

...