Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Более элегантное решение / 7 сообщений из 7, страница 1 из 1
18.07.2017, 16:39
    #39490968
Adtain
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Более элегантное решение
ПРИМЕР 1: Предлагается следующий набор данных:

Начало действияСотрудникДолжность 01.01.2017 Men 1 Job 101.02.2017Men 1Job 101.03.2017Men 1Job 301.04.2017Men 1Job 401.05.2017Men 1 Job 4
РЕЗУЛЬТАТ: Если один и тот же сотрудник меняет подряд должность, то его необходимо сгруппировать, взял самую первую дату начала и самую последнюю должность:

Начало действияСотрудникДолжность01.01.2017Men 1Job 4
ПРИМЕР 2: Соответственно, если имеем в одной таблице несколько разных сотрудников:

Начало действияСотрудникДолжность 01.01.2017 Men 1 Job 1 01.02.2017 Men 2 Job 101.03.2017Men 2Job 301.04.2017Men 2 Job 4 01.05.2017 Men 1 Job 4
РЕЗУЛЬТАТ: То группировка должна учитывать только непрерывные интервалы работы сотрудников:

Начало действияСотрудникДолжность01.01.2017Men 1Job 101.02.2017Men 2Job 401.05.2017Men 1Job 4
Предлагаемое мною решение на первый взгляд кажется громоздким, хочется упросить:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
with tst as ( select to_date('01.01.2017', 'dd.mm.yyyy') dat, 'Men 1' fio, 'Job 1' job from dual union all
              select to_date('01.02.2017', 'dd.mm.yyyy') dat, 'Men 1' fio, 'Job 2' job from dual union all
              select to_date('01.04.2017', 'dd.mm.yyyy') dat, 'Men 1' fio, 'Job 3' job from dual union all
              select to_date('01.05.2017', 'dd.mm.yyyy') dat, 'Men 1' fio, 'Job 4' job from dual union all
              select to_date('01.06.2017', 'dd.mm.yyyy') dat, 'Men 2' fio, 'Job 1' job from dual union all
              select to_date('01.07.2017', 'dd.mm.yyyy') dat, 'Men 2' fio, 'Job 1' job from dual union all
              select to_date('01.08.2017', 'dd.mm.yyyy') dat, 'Men 1' fio, 'Job 2' job from dual union all
              select to_date('01.09.2017', 'dd.mm.yyyy') dat, 'Men 3' fio, 'Job 1' job from dual union all
              select to_date('01.10.2017', 'dd.mm.yyyy') dat, 'Men 1' fio, 'Job 4' job from dual union all
              select to_date('01.11.2017', 'dd.mm.yyyy') dat, 'Men 1' fio, 'Job 1' job from dual union all
              select to_date('01.11.2017', 'dd.mm.yyyy') dat, 'Men 1' fio, 'Job 2' job from dual)

select max(decode(t.gr1, 1, t.dat)) dat,
       t.fio,
       max(decode(t.gr2, 1, t.job)) job
  from (select t.*,
               sum(t.gr1) over(order by t.dat rows between unbounded preceding and current row) gr
          from (select t.dat,
                       t.fio,
                       t.job,
                       decode(t.fio, lag(t.fio)  over(order by t.dat), null, 1) gr1,
                       decode(t.fio, lead(t.fio) over(order by t.dat), null, 1) gr2
                  from tst t) t) t
 group by t.gr, t.fio
...
Рейтинг: 0 / 0
18.07.2017, 16:48
    #39490972
Elic
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Более элегантное решение
Adtain
Код: plsql
1.
max(decode(t.gr1, 1, t.dat)) dat,

Просто minAdtain
Код: plsql
1.
max(decode(t.gr2, 1, t.job)) job

Просто first/lastAdtain
Код: plsql
1.
over(order by t.dat rows between unbounded preceding and current row)

Не обязательно.
...
Рейтинг: 0 / 0
18.07.2017, 16:49
    #39490973
Elic
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Более элегантное решение
Adtain
Код: plsql
1.
group by t.gr, t.fio

Не нужно
...
Рейтинг: 0 / 0
18.07.2017, 17:16
    #39491015
AmKad
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Более элегантное решение
Adtain,

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
with tst as ( select to_date('01.01.2017', 'dd.mm.yyyy') dat, 'Men 1' fio, 'Job 1' job from dual union all
              select to_date('01.02.2017', 'dd.mm.yyyy') dat, 'Men 1' fio, 'Job 2' job from dual union all
              select to_date('01.04.2017', 'dd.mm.yyyy') dat, 'Men 1' fio, 'Job 3' job from dual union all
              select to_date('01.05.2017', 'dd.mm.yyyy') dat, 'Men 1' fio, 'Job 4' job from dual union all
              select to_date('01.06.2017', 'dd.mm.yyyy') dat, 'Men 2' fio, 'Job 1' job from dual union all
              select to_date('01.07.2017', 'dd.mm.yyyy') dat, 'Men 2' fio, 'Job 1' job from dual union all
              select to_date('01.08.2017', 'dd.mm.yyyy') dat, 'Men 1' fio, 'Job 2' job from dual union all
              select to_date('01.09.2017', 'dd.mm.yyyy') dat, 'Men 3' fio, 'Job 1' job from dual union all
              select to_date('01.10.2017', 'dd.mm.yyyy') dat, 'Men 1' fio, 'Job 4' job from dual union all
              select to_date('01.11.2017', 'dd.mm.yyyy') dat, 'Men 1' fio, 'Job 1' job from dual union all
              select to_date('01.11.2017', 'dd.mm.yyyy') dat, 'Men 1' fio, 'Job 2' job from dual)
select min(dat) dat, fio,
max(job) keep (dense_rank last order by dat) job
from
   (select dat, fio, job,
    row_number() over (partition by fio order by dat) rn_men,
    row_number() over (                 order by dat) rn
    from tst
   )
group by rn - rn_men, fio
order by 1,2,3;

DAT        FIO   JOB
---------- ----- -----
2017-01-01 Men 1 Job 4
2017-06-01 Men 2 Job 1
2017-08-01 Men 1 Job 2
2017-09-01 Men 3 Job 1
2017-10-01 Men 1 Job 2
...
Рейтинг: 0 / 0
18.07.2017, 17:31
    #39491036
AmKad
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Более элегантное решение
Уменьшим количество сортировок в плане и выкинем группировку.
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
select dat, fio, fv_job as job
from
   (select t.*,
    first_value(decode(ls_last, 1, job) ignore nulls) over (order by dat rows between current row and unbounded following) fv_job
    from
       (select tst.*,
        decode(fio, lag (fio) over (order by dat), 0, 1) is_first,
        decode(fio, lead(fio) over (order by dat), 0, 1) ls_last
        from tst
       ) t
   )t
where is_first = 1;

DAT        FIO   JOB
---------- ----- -----
2017-01-01 Men 1 Job 4
2017-06-01 Men 2 Job 1
2017-08-01 Men 1 Job 2
2017-09-01 Men 3 Job 1
2017-10-01 Men 1 Job 2
...
Рейтинг: 0 / 0
18.07.2017, 17:43
    #39491060
Adtain
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Более элегантное решение
Elic,
AmKad,

Спасибо большое за решения!
...
Рейтинг: 0 / 0
18.07.2017, 19:11
    #39491127
andrey_anonymous
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Более элегантное решение
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
> with tst as ( select to_date('01.01.2017', 'dd.mm.yyyy') dat, 'Men 1' fio, 'Job 1' job from dual union all
              select to_date('01.02.2017', 'dd.mm.yyyy') dat, 'Men 1' fio, 'Job 2' job from dual union all
              select to_date('01.04.2017', 'dd.mm.yyyy') dat, 'Men 1' fio, 'Job 3' job from dual union all
              select to_date('01.05.2017', 'dd.mm.yyyy') dat, 'Men 1' fio, 'Job 4' job from dual union all
              select to_date('01.06.2017', 'dd.mm.yyyy') dat, 'Men 2' fio, 'Job 1' job from dual union all
              select to_date('01.07.2017', 'dd.mm.yyyy') dat, 'Men 2' fio, 'Job 1' job from dual union all
              select to_date('01.08.2017', 'dd.mm.yyyy') dat, 'Men 1' fio, 'Job 2' job from dual union all
              select to_date('01.09.2017', 'dd.mm.yyyy') dat, 'Men 3' fio, 'Job 1' job from dual union all
              select to_date('01.10.2017', 'dd.mm.yyyy') dat, 'Men 1' fio, 'Job 4' job from dual union all
              select to_date('01.11.2017', 'dd.mm.yyyy') dat, 'Men 1' fio, 'Job 1' job from dual union all
              select to_date('01.11.2017', 'dd.mm.yyyy') dat, 'Men 1' fio, 'Job 2' job from dual)
-----------------------------------------
select * from tst
match_recognize(
  order by dat
  measures strt.dat as dat
         , strt.fio as fio
         , last(job) as job
  one row per match
  pattern(strt men*)
  define
    men as men.fio = prev(men.fio)
) t

DAT        FIO   JOB 
---------- ----- -----
2017-01-01 Men 1 Job 4 
2017-06-01 Men 2 Job 1 
2017-08-01 Men 1 Job 2 
2017-09-01 Men 3 Job 1 
2017-10-01 Men 1 Job 2 
...
Рейтинг: 0 / 0
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Более элегантное решение / 7 сообщений из 7, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]