Reputation: 135
I have a child table that contains the history of statuses for the particular parent record.
The table would be:
Parent_id NUMBER(38)
Date_Created DATE
Status VARCHAR2(15)
Sample Data:
1, sysdate-20, REQ
1, sysdate-10, INPRG
1, sysdate-5, WAIT
1, sysdate-2, INPRG
1, sysdate, COMP
For any particular parent_id, how can I calculate the total time a parent_id stayed in a particular status? Given that the calculation is the date next status was created minus the teh date record was created. Keeping in mind that the status can occur multiple times.
For the sample data, how could you calculate the total time the record was in "INPRG" status?
It has to be done entirely in Oracle SQL. No functions, procedures, packages, etc.
Thanks in advance.
Upvotes: 1
Views: 2339
Reputation: 4174
I primarily use SQL Server, not Oracle, so forgive me if my syntax is a little off...
with base as (
select Parent_id, Date_Created, Status,
row_number() over(partition by Parent_id order by Date_Created) as 'row'
from Table
)
select Parent_id, Status, sum(timeInStatus)
from (
select this.Parent_id, this.Status,
next.Date_Created-this.Date_Created as 'timeInStatus'
from base this
join base next on this.Parent_id=next.Parent_id
and this.row=next.row-1
) t
where Status = 'INPRG'
group by Parent_id, Status
The basic concept is to utilize row_number
to self join each row to it's next row and compute the time between them. Then it's just a simple aggregation of that data to get the answer you want.
Upvotes: 1
Reputation: 231651
You can use the analytic function LEAD
and LAG
to access data from the next or prior row in the result set. Something like this will give you the total time in each status
SQL> ed
Wrote file afiedt.buf
1 with t as (
2 select 1 parent_id, sysdate-20 date_created, 'REQ' status from dual
3 union all
4 select 1, sysdate-10, 'INPRG' from dual
5 union all
6 select 1, sysdate-5, 'WAIT' from dual
7 union all
8 select 1, sysdate-2, 'INPRG' from dual
9 union all
10 select 1, sysdate, 'COMP' from dual
11 )
12 select parent_id,
13 status,
14 sum(time_in_status)
15 from (
16 select parent_id,
17 date_created,
18 nvl(lead(date_created) over
19 (partition by parent_id
20 order by date_created),
21 sysdate) next_status_date,
22 nvl(lead(date_created) over
23 (partition by parent_id
24 order by date_created),
25 sysdate) -
26 date_created time_in_status,
27 status
28 from t)
29* group by parent_id, status
SQL> /
PARENT_ID STATU SUM(TIME_IN_STATUS)
---------- ----- -------------------
1 REQ 10
1 COMP 0
1 WAIT 3
1 INPRG 7
Upvotes: 3