Home > Enterprise >  Average Time Duration
Average Time Duration

Time:10-06

Afternoon All,

I'm pulling my non-existent hair out on this...

Trying to work out the average duration a specific task occurs from start to finish.

Simplified version of table:

Code Dstamp ID
Allocate 14-SEP-22 10.42.40.530304000 1234
Replenish 14-SEP-22 19.42.40.530304000 1234
Allocate 15-SEP-22 13.36.40.530304000 5678
Replenish 15-SEP-22 18.12.40.530304000 5678
Allocate 16-SEP-22 09.42.40.530304000 9101
Replenish 16-SEP-22 21.42.40.530304000 9101

I'm pretty new to SQL, so it's probably something really simple - I have a feeling that I would either need to use LAG or Union (or possibly both!) but not sure if I'm overthinking it!

There are a number of different lines in the table with the same ID but these will be ignored under a where clause, so will just be focusing on the Allocate/Replenish rows.

Any help will be appreciated!

CodePudding user response:

You could use lead/lag, but you can also use aggregation, which could be conditional to effectively ignore any that only have one of the codes:

select id,
  max(case when code = 'Replenish' then dstamp end)
    - min(case when code = 'Allocate' then dstamp end) as diff
from your_table
group by id
ID DIFF
1234 000000000 09:00:00.000000000
5678 000000000 04:36:00.000000000
9101 000000000 12:00:00.000000000

But you can't directly average an interval. One option is to convert the intervals to the equivalent number of seconds, which you can do with extract(), maybe using a CTE to avoid repeating the calculation:

with cte (id, diff) as (
  select id,
    max(case when code = 'Replenish' then dstamp end)
      - min(case when code = 'Allocate' then dstamp end)
  from your_table
  group by id
)
select id, diff,
  extract(day from diff) * 86400
      extract(hour from diff) * 3600
      extract(minute from diff) * 60
      extract(second from diff) as diff_seconds
from cte
ID DIFF DIFF_SECONDS
1234 000000000 09:00:00.000000000 32400
5678 000000000 04:36:00.000000000 16560
9101 000000000 12:00:00.000000000 43200

then average those numbers, and convert that back to an interval (or whatever data type you need):

with cte (id, diff) as (
  select id,
    max(case when code = 'Replenish' then dstamp end)
      - min(case when code = 'Allocate' then dstamp end)
  from your_table
  group by id
)
select avg(
  extract(day from diff) * 86400
      extract(hour from diff) * 3600
      extract(minute from diff) * 60
      extract(second from diff)
  ) * interval '1' second as avg_diff
from cte
AVG_DIFF
000000000 08:32:00.000000000

fiddle

If you have an ID that only has 'Allocate' then that won't affect the result; and this should work even if you didn't filter out the other code values first.

  • Related