Выберите дату начала / окончания для каждой группы - PullRequest
1 голос
/ 08 июля 2019

У меня есть таблица назначений сотрудников в форме, показанной ниже:

<b>emp_id, dept_id, assignment,  start_dt,    end_dt</b>
1,      10,      project 1,   2001-01-01,  2001-12-31
1,      10,      project 2,   2002-01-01,  2002-12-31
1,      20,      project 3,   2003-01-01,  2003-12-31
1,      20,      project 4,   2004-01-01,  2004-12-31
1,      10,      project 5,   2005-01-01,  2005-12-31

Из приведенной выше таблицы мне нужно обобщить историю отдела сотрудников, т. Е. Продолжительность работы сотрудника в определенном отделе до перевода вкакой-то другой отдел.

Ожидаемый результат Результат показан ниже:

<b>emp_id, dept_id,  start_dt,    end_dt</b>
1,      10,       2001-01-01,  2002-12-31
1,      20,       2003-01-01,  2004-12-31
1,      10,       2005-01-01,  2005-12-31

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

    select distinct emp_id, dept_id, start_dt, end_dt 
    from ( 
       select emp_id, dept_id, 
              min(start_date) 
                 over (partition by emp_id, dept_id order by emp_id, dept_id 
                 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as start_dt,
              max(end_date)   
                 over (partition by emp_id, dept_id order by emp_id, dept_id 
                 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as end_dt
       from employee_job_assignment
    )
    where emp_id = 1;

Приведенный выше запрос приводит к следующему выводу:

<b>emp_id, dept_id,  start_dt,    end_dt</b>
1,      10,       2001-01-01,  2005-12-31
1,      20,       2003-01-01,  2004-12-31

Ответы [ 3 ]

1 голос
/ 08 июля 2019

Ключом к решению является разделение строк на группы в соответствии с вашей логикой. Вы можете сделать это, используя функцию LAG(). Например:

select
  max(emp_id) as emp_id,
  max(dept_id) as dept_id,
  min(start_dt) as start_dt,
  max(end_dt) as end_dt
from (
  select
    *,
    sum(inc) over(partition by emp_id order by start_dt) as grp
  from (
    select
      *,
      case when lag(dept_id) over(partition by emp_id order by start_dt) 
                <> dept_id then 1 else 0 end as inc
    from employee_job_assignment
  ) x
) y
group by grp
order by grp
1 голос
/ 08 июля 2019

Это проблема пробелов и островков.Но с изюминкой.В этом случае вы, вероятно, также захотите учесть пробелы в одном отделе.Например:

emp_id, dept_id, assignment,  start_dt,    end_dt
1,      10,      project 1,   2001-01-01,  2001-12-31
1,      10,      project 2,   2003-01-01,  2003-12-31

Это должно вернуть две строки, а не одну.

Для этого определите, где начинается каждый остров, сравнивая предыдущую дату окончания с текущей датой начала.Это определяет начало группировки.Остальное агрегация:

select emp_id, dept_id, min(start_dt), max(end_dt)
from (select eja.*,
             sum(case when prev_end_dt = start_dt - 1
                      then 0 else 1
                 end) over (partition by emp_id, dept_id) as grouping
      from (select eja.*,
                   lag(end_dt) over (partition by emp_id, dept_id order by start_dt) as prev_end_dt
            from employee_job_assignment eja
           ) eja
     ) eja
group by emp_id, dept_id, grouping;
1 голос
/ 08 июля 2019

Вы можете попробовать ниже -

select emp_id,dept_id,min(start_Date) as start_Date,min(end_date) as end_date
from
(
select *,
row_number() over(order by start_date)-row_number() over(partition by dept_id order by start_date) as grp
from t
)A group by grp, dept_id,emp_id

ВЫВОД:

emp_id  dept_id start_Date              end_date
 1       10      01/01/2001 00:00:00    31/12/2001 00:00:00
 1       10      01/01/2005 00:00:00    31/12/2005 00:00:00
 1       20      01/01/2003 00:00:00    31/12/2003 00:00:00
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...