MATCH_RECOGNIZE
В Oracle 12.1 и выше вы можете легко сделать это с помощью предложения match_recognize
.
alter session set nls_date_format = 'yyyy-mm-dd hh24:mi:ss';
with register (id, book_id, client_id, type_, date_) as (
select 1, 2447, 274761, 1, to_date('2020-04-07 09:38:54') from dual union all
select 2, 2447, 274761, 2, to_date('2020-04-07 09:39:25') from dual union all
select 3, 2447, 274761, 1, to_date('2020-04-07 09:39:53') from dual union all
select 4, 2447, 274761, 2, to_date('2020-04-07 09:41:03') from dual union all
select 5, 1000, 274761, 1, to_date('2020-04-07 09:52:05') from dual union all
select 6, 2447, 274761, 1, to_date('2020-04-07 10:04:54') from dual union all
select 7, 1000, 274761, 2, to_date('2020-04-07 10:05:38') from dual union all
select 8, 2447, 274761, 2, to_date('2020-04-07 10:06:04') from dual union all
select 9, 3002, 274761, 1, to_date('2020-04-07 11:22:02') from dual
)
select *
from register
match_recognize(
partition by book_id, client_id
order by date_
measures i.date_ as date_in, o.date_ as date_out
pattern ( i o? )
define i as type_ = 1, o as type_ = 2
)
order by client_id, date_in, book_id
;
BOOK_ID CLIENT_ID DATE_IN DATE_OUT
------- --------- ------------------- -------------------
2447 274761 2020-04-07 09:38:54 2020-04-07 09:39:25
2447 274761 2020-04-07 09:39:53 2020-04-07 09:41:03
1000 274761 2020-04-07 09:52:05 2020-04-07 10:05:38
2447 274761 2020-04-07 10:04:54 2020-04-07 10:06:04
3002 274761 2020-04-07 11:22:02
Несколько замечаний: TYPE
, DATE
, IN
являются ключевыми словами Oracle (последние два являются даже зарезервированными ключевыми словами), поэтому они не должны быть именами столбцов ни на входе, ни на выходе. Я изменил первые два на TYPE_
и DATE_
(с завершающим подчеркиванием) и назвал выходные столбцы DATE_IN
и DATE_OUT
. Кроме того, я изменил имя столбца BOOOK_ID
на BOOK_ID
, и вы бы поступили так же; в словаре английского языка sh есть только две буквы, а не три.
Затем - если вы попробуете это в SQL Developer, вы обнаружите, что знак вопроса в предложении PATTERN
в MATCH_RECOGNIZE
выдает ошибку. Это дефект в SQL Developer; если вы выполните тот же запрос в SQL* Plus или других интерфейсах, он будет работать просто отлично. В SQL Developer вам необходимо изменить o?
на эквивалентное выражение o{0,1}
.
= = = =
PIVOT
В Oracle 11.1 и выше вы можете сделать это с помощью оператора PIVOT
. Вам нужна подготовительная работа (подзапрос), чтобы сопоставить события "in" и "out" парам; функция analyti c ROW_NUMBER()
, разделенная на книги, клиент и тип , - это простой способ сделать это.
select client_id, book_id, date_in, date_out
from ( select client_id, book_id, type_, date_,
row_number() over (partition by book_id, client_id, type_
order by date_) as rn
from register r
)
pivot (max(date_) for type_ in (1 as date_in, 2 as date_out))
order by client_id, book_id, date_in
;