Hello,
I need some help with an Oracle Sql Query. For each day i must calculate the time difference between each cycle IN & OUT and then sum the difference as total worked minutes. The main problem that i have it's that the input data is variable, so i can have 1 or 2 or 3 or N time with the status IN and 1 or 2 or 3 or N time with the status OUT. So i used the analytical function of row_number+1 for set IN and row_number for set OUT, but i cannot determine always the max(time) for IN or OUT status per each cycle.
P.S. My problem that i have it is that for the day 30 for the cycle 3 i have the pair 30-01-2018 13:02:21--OUT and 30-01-2018 12:52:16--IN, and i need the OUT to be 30-01-2018 14:55:02--OUT, the same issue for the day 31
at the first cycle where i have the pair 31-01-2018 10:03:58--OUT and
31-01-2018 10:02:39--IN and i need OUT to be 31-01-2018 11:11:33--OUT
Thank you for the support !
create table test
(
time date not null
,evolutionid int not null
,in_out_status varchar2(3) not null
);
insert into test (time,evolutionid,in_out_status)
values (To_Date('1/29/2018 9:52:34 AM', 'mm-dd-yyyy HH:MI:SS AM'),101,'IN');
insert into test (time,evolutionid,in_out_status)
values (To_Date('1/29/2018 9:52:54 AM', 'mm-dd-yyyy HH:MI:SS AM'),100,'OUT');
insert into test (time,evolutionid,in_out_status)
values (To_Date('1/29/2018 9:54:10 AM', 'mm-dd-yyyy HH:MI:SS AM'),99,'IN');
insert into test (time,evolutionid,in_out_status)
values (To_Date('1/29/2018 10:28:27 AM', 'mm-dd-yyyy HH:MI:SS AM'),98,'IN');
insert into test (time,evolutionid,in_out_status)
values (To_Date('1/29/2018 11:43:50 AM', 'mm-dd-yyyy HH:MI:SS AM'),97,'IN');
insert into test (time,evolutionid,in_out_status)
values (To_Date('1/29/2018 12:37:40 PM', 'mm-dd-yyyy HH:MI:SS AM'),96,'IN');
insert into test (time,evolutionid,in_out_status)
values (To_Date('1/29/2018 12:37:57 PM', 'mm-dd-yyyy HH:MI:SS AM'),95,'OUT');
insert into test (time,evolutionid,in_out_status)
values (To_Date('1/29/2018 2:16:59 PM', 'mm-dd-yyyy HH:MI:SS AM'),94,'IN');
insert into test (time,evolutionid,in_out_status)
values (To_Date('1/29/2018 2:58:00 PM', 'mm-dd-yyyy HH:MI:SS AM'),93,'IN');
insert into test (time,evolutionid,in_out_status)
values (To_Date('1/29/2018 3:34:22 PM', 'mm-dd-yyyy HH:MI:SS AM'),92,'IN');
insert into test (time,evolutionid,in_out_status)
values (To_Date('1/29/2018 4:20:06 PM', 'mm-dd-yyyy HH:MI:SS AM'),91,'IN');
insert into test (time,evolutionid,in_out_status)
values (To_Date('1/29/2018 4:31:36 PM', 'mm-dd-yyyy HH:MI:SS AM'),90,'OUT');
insert into test (time,evolutionid,in_out_status)
values (To_Date('1/29/2018 4:56:48 PM', 'mm-dd-yyyy HH:MI:SS AM'),89,'IN');
insert into test (time,evolutionid,in_out_status)
values (To_Date('1/30/2018 9:53:08 AM', 'mm-dd-yyyy HH:MI:SS AM'),88,'IN');
insert into test (time,evolutionid,in_out_status)
values (To_Date('1/30/2018 10:24:15 AM', 'mm-dd-yyyy HH:MI:SS AM'),87,'OUT');
insert into test (time,evolutionid,in_out_status)
values (To_Date('1/30/2018 10:25:09 AM', 'mm-dd-yyyy HH:MI:SS AM'),86,'IN');
insert into test (time,evolutionid,in_out_status)
values (To_Date('1/30/2018 10:55:11 AM', 'mm-dd-yyyy HH:MI:SS AM'),85,'OUT');
insert into test (time,evolutionid,in_out_status)
values (To_Date('1/30/2018 11:12:52 AM', 'mm-dd-yyyy HH:MI:SS AM'),84,'IN');
insert into test (time,evolutionid,in_out_status)
values (To_Date('1/30/2018 12:52:16 PM', 'mm-dd-yyyy HH:MI:SS AM'),83,'IN');
insert into test (time,evolutionid,in_out_status)
values (To_Date('1/30/2018 1:02:21 PM', 'mm-dd-yyyy HH:MI:SS AM'),82,'OUT');
insert into test (time,evolutionid,in_out_status)
values (To_Date('1/30/2018 2:55:02 PM', 'mm-dd-yyyy HH:MI:SS AM'),81,'OUT');
insert into test (time,evolutionid,in_out_status)
values (To_Date('1/30/2018 2:57:09 PM', 'mm-dd-yyyy HH:MI:SS AM'),80,'IN');
insert into test (time,evolutionid,in_out_status)
values (To_Date('1/30/2018 3:37:14 PM', 'mm-dd-yyyy HH:MI:SS AM'),79,'IN');
insert into test (time,evolutionid,in_out_status)
values (To_Date('1/30/2018 4:53:42 PM', 'mm-dd-yyyy HH:MI:SS AM'),78,'IN');
insert into test (time,evolutionid,in_out_status)
values (To_Date('1/30/2018 5:56:30 PM', 'mm-dd-yyyy HH:MI:SS AM'),77,'IN');
insert into test (time,evolutionid,in_out_status)
values (To_Date('1/30/2018 6:01:58 PM', 'mm-dd-yyyy HH:MI:SS AM'),76,'OUT');
insert into test (time,evolutionid,in_out_status)
values (To_Date('1/31/2018 10:02:39 AM', 'mm-dd-yyyy HH:MI:SS AM'),75,'IN');
insert into test (time,evolutionid,in_out_status)
values (To_Date('1/31/2018 10:03:58 AM', 'mm-dd-yyyy HH:MI:SS AM'),74,'OUT');
insert into test (time,evolutionid,in_out_status)
values (To_Date('1/31/2018 11:11:33 AM', 'mm-dd-yyyy HH:MI:SS AM'),73,'OUT');
insert into test (time,evolutionid,in_out_status)
values (To_Date('1/31/2018 11:16:01 AM', 'mm-dd-yyyy HH:MI:SS AM'),72,'IN');
insert into test (time,evolutionid,in_out_status)
values (To_Date('1/31/2018 11:30:16 AM', 'mm-dd-yyyy HH:MI:SS AM'),71,'OUT');
insert into test (time,evolutionid,in_out_status)
values (To_Date('1/31/2018 11:52:41 AM', 'mm-dd-yyyy HH:MI:SS AM'),70,'IN');
insert into test (time,evolutionid,in_out_status)
values (To_Date('1/31/2018 12:11:36 PM', 'mm-dd-yyyy HH:MI:SS AM'),69,'OUT');
insert into test (time,evolutionid,in_out_status)
values (To_Date('1/31/2018 5:33:18 PM', 'mm-dd-yyyy HH:MI:SS AM'),68,'IN');
insert into test (time,evolutionid,in_out_status)
values (To_Date('1/31/2018 6:25:50 PM', 'mm-dd-yyyy HH:MI:SS AM'),67,'IN');
insert into test (time,evolutionid,in_out_status)
values (To_Date('1/31/2018 7:06:11 PM', 'mm-dd-yyyy HH:MI:SS AM'),66,'OUT');
insert into test (time,evolutionid,in_out_status)
values (To_Date('1/31/2018 7:07:30 PM', 'mm-dd-yyyy HH:MI:SS AM'),65,'IN');
insert into test (time,evolutionid,in_out_status)
values (To_Date('1/31/2018 7:10:54 PM', 'mm-dd-yyyy HH:MI:SS AM'),64,'OUT');
-- truncate table test;
alter session set nls_date_format = 'dd-mm-yyyy hh24:mi:ss';
select
BB.time_BB
,BB.in_out_status_BB
,AA.time_AA
,AA.in_out_status_AA
,round(((BB.time_BB - AA.time_AA) * 24 * 60),2) AS diff_time_minutes
from
(SELECT
time as time_AA
,in_out_status as in_out_status_AA
,row_number() over ( order by evolutionid desc) as rn_AA
FROM
test) AA
inner join
(SELECT
time as time_BB
,in_out_status as in_out_status_BB
,row_number() over ( order by evolutionid desc) as rn_BB
FROM
test) BB
on AA.rn_AA+1 = BB.rn_BB -- and mod (AA.rn_AA,2)= 0
and AA.in_out_status_AA not like 'OUT' and BB.in_out_status_BB not like 'IN'
order by AA.TIME_AA ;
So you have a sequence of rows ins and outs:
IN *
OUT *
IN
IN *
OUT
OUT *
IN
IN
IN *
OUT
OUT
OUT *
And you want to pair the last IN with last OUT after it before the next IN? i.e. the rows with stars next to them?
If so, this is another problem match_recognize makes easy!
Look for a pattern of one or more INs followed by one or more OUTs. And return the last time for each:
select *
from test match_recognize (
order by time
measures
last (time_in.time) as last_in,
last (time_out.time) as last_out
pattern ( time_in+ time_out+ )
define
time_in as in_out_status = 'IN',
time_out as in_out_status = 'OUT'
);
LAST_IN LAST_OUT
29-01-2018 09:52:34 29-01-2018 09:52:54
29-01-2018 12:37:40 29-01-2018 12:37:57
29-01-2018 16:20:06 29-01-2018 16:31:36
30-01-2018 09:53:08 30-01-2018 10:24:15
30-01-2018 10:25:09 30-01-2018 10:55:11
30-01-2018 12:52:16 30-01-2018 14:55:02
30-01-2018 17:56:30 30-01-2018 18:01:58
31-01-2018 10:02:39 31-01-2018 11:11:33
31-01-2018 11:16:01 31-01-2018 11:30:16
31-01-2018 11:52:41 31-01-2018 12:11:36
31-01-2018 18:25:50 31-01-2018 19:06:11
31-01-2018 19:07:30 31-01-2018 19:10:54
Sadly, this is a 12c feature. And you're on 11g. So you need something a little different...
One way to do this is:
- Use a variant of the Tabibitosan method to group consecutive INs and OUTs
- This will lump together consecutive times for each status, but there will be gaps in the values. This makes it hard to know which IN links with which OUT.
- Renumber the groups with consecutive numbers starting at 1 for IN and OUT. Dense_rank will do this
- Pivot the results
Which gives:
with tabibitosan as (
select time, in_out_status,
row_number() over (order by time) -
row_number() over (partition by in_out_status order by time) grp
from test
), grps as (
select dense_rank() over ( partition by in_out_status order by grp ) dr,
t.time, t.in_out_status
from tabibitosan t
)
select *
from grps
pivot (
max(time) for
in_out_status in ( 'IN' last_in, 'OUT' last_out)
)
order by dr;
DR LAST_IN LAST_OUT
1 29-JAN-2018 09:52:34 29-JAN-2018 09:52:54
2 29-JAN-2018 12:37:40 29-JAN-2018 12:37:57
3 29-JAN-2018 16:20:06 29-JAN-2018 16:31:36
4 30-JAN-2018 09:53:08 30-JAN-2018 10:24:15
5 30-JAN-2018 10:25:09 30-JAN-2018 10:55:11
6 30-JAN-2018 12:52:16 30-JAN-2018 14:55:02
7 30-JAN-2018 17:56:30 30-JAN-2018 18:01:58
8 31-JAN-2018 10:02:39 31-JAN-2018 11:11:33
9 31-JAN-2018 11:16:01 31-JAN-2018 11:30:16
10 31-JAN-2018 11:52:41 31-JAN-2018 12:11:36
11 31-JAN-2018 18:25:50 31-JAN-2018 19:06:11
12 31-JAN-2018 19:07:30 31-JAN-2018 19:10:54