I have a table of time periods with an active incident in the format:
Incident_Start | Incident_End |
---|---|
1/1/2022 01:05 | 1/1/2022 03:00 |
1/2/2022 05:00 | 1/5/2022 12:34 |
2/5/2022 13:00 | 2/6/2022 16:22 |
… | … |
I now need to transform this into a table of dates with the total minutes an incident was active during each date like:
Date | Incident Minutes |
---|---|
1/1/2022 | 115 |
1/2/2022 | 1140 |
1/3/2022 | 1440 |
1/4/2022 | 1440 |
1/5/2022 | 754 |
1/6/2022 | 0 |
… | … |
I am able to do this easily via Python/JavaScript like (in pseudo-code, very naively):
dates = [dates between start_date, end_date]
for (date in dates):
if (impact_periods.filter(start_date <= date && end_date >= date).length > 0):
outage_mins = 1440
else if (impact_periods.filter(start_date >= date && end_date <= date).length > 0):
outage_mins = sum(impact_periods.filter(start_date >= date && end_date <= date).outage_mins)
etc
Now I’d like to do this with a SQL query, but I’m not sure how. Obviously, I’ll start by creating a date table between the dates I’m interested in:
SELECT
dd day_start,
dd::date + 1 - interval '1 sec' AS day_end
FROM
generate_series (
'date_start' :: timestamp,
'date_end' :: timestamp,
'1 day' :: interval
) dd
But now I’m not sure how to sum the impact mins on each day, taking into account that some incidents may start before the day and end during, or start during the day and end after.
Can someone point me in the right direction of how to solve this? Any help is greatly appreciated!
2
Answers
You can try this solution which
A/ generates a set of timestamp ranges which correspond to the calendar days
B/ select the dates which intersect with the incident time ranges
C/ calculate the duration in minutes of the date / incident time intersection :
see the result in dbfiddle
You can
cross join
a datetime series of the dates between the start and end of the incident:See fiddle