Oracle 12c - выбрать записи в окне - PullRequest
0 голосов
/ 06 декабря 2018

У меня есть следующие примеры записей:

log_id employee_id
12345  99999      
12346  99999      
12347  88888      
12357  88888 

Как отфильтровать записи, где log_id = 12345, 12346 (log_id только с одним номером) при наличии дубликатов employee_id?Вывод должен быть:

log_id employee_id
12345  99999      
12346  99999 

Ответы [ 4 ]

0 голосов
/ 07 декабря 2018

Предполагая, что эта структура таблицы:

create table test (
  log_id number(5) primary key,
  employee_id number(5) not null
)

Этот пример данных:

insert into test
   (select 12342, 99999 from dual union all
    select 12343, 77777 from dual union all
    select 12344, 99999 from dual union all
    select 12345, 99999 from dual union all
    select 12346, 99999 from dual union all
    select 12347, 88888 from dual union all
    -- gap
    select 12357, 88888 from dual union all
    select 12358, 33333 from dual union all
    select 12359, 33333 from dual
   )

Вы можете сделать это с помощью этого запроса:

with x as (
 select log_id,
        employee_id,
        lead(log_id) over (order by log_id) as next_log_id,
        lag(log_id) over (order by log_id) as previous_log_id,
        lead(employee_id) over (order by log_id) as next_employee_id,
        lag(employee_id) over (order by log_id) as previous_employee_id
 from test
)
select log_id, employee_id
  from x
 where (log_id = next_log_id - 1 and employee_id = next_employee_id)
    or (log_id = previous_log_id + 1 and employee_id = previous_employee_id)
 order by 1

С этим результатом:

LOG_ID | EMPLOYEE_ID
-------+------------
 12344 |       99999
 12345 |       99999
 12346 |       99999
 12358 |       33333
 12359 |       33333

Если вам гарантировано, что последовательность значений LOG_ID без пропусков (поскольку выборка находится в диапазоне от 12342 до 12347), вы можете использовать более простой вариант:

with x as (
 select log_id,
        employee_id,
        lead(employee_id) over (order by log_id) as next_employee_id,
        lag(employee_id) over (order by log_id) as previous_employee_id
 from test
 where log_id between 12342 and 12347
)
select log_id, employee_id
  from x
 where employee_id in (previous_employee_id, next_employee_id)
 order by 1

Вы можете увидеть его в действии на этом Oracle LiveSQL или SQL Fiddle .

0 голосов
/ 06 декабря 2018

Я бы не использовал оконные функции.Я бы просто использовал exists:

select t.*
from t
where exists (select 1
              from t tnext
              where tnext.log_id = t.log_id + 1 and tnext.employee_id = t.employee_id) or
      exists (select 1
              from t tprev
              where tprev.log_id = t.log_id - 1 and tprev.employee_id = t.employee_id);

Этот запрос должен иметь возможность использовать индекс на (employee_id, log_id).

0 голосов
/ 06 декабря 2018

Еще один вариант:

SQL> with test (log_id, employee_id) as
  2    (select 12345, 99999 from dual union all
  3     select 12346, 99999 from dual union all
  4     select 12344, 99999 from dual union all  --> added this one
  5     --
  6     select 12347, 88888 from dual union all
  7     select 12357, 88888 from dual
  8    )
  9  select log_id, employee_id
 10  from test
 11  where employee_id in (select employee_id
 12                        from test
 13                        group by employee_id
 14                        having max(log_id) - min(log_id) = count(*) - 1
 15                       );

    LOG_ID EMPLOYEE_ID
---------- -----------
     12344       99999
     12346       99999
     12345       99999

SQL>
0 голосов
/ 06 декабря 2018

Я бы попробовал что-то вроде этого:

with 
x as (
  select log_id, employee_id, row_number() over(order by log_id) as rn
  from my_table
),
y as (
  select
    log_id, employee_id, rn,
    lag(log_id) over(order by rn) as prev_log_id,
    lead(log_id) over(order by rn) as next_log_id
from x
)
select log_id, employee_id from y
where log_id - 1 = prev_log_id or prev_log_id is null
  and log_id + 1 = next_log_id or next_log_is is null
order by rn
...