I'm trying to calculate the service hours that have passed since a ticket has been logged. When a ticket gets logged a timestamp is saved with it ( date_logged ). When it gets closed another timestamp is saved ( date_closed ).
What I need is the hours that have passed between the date_logged and the current datetime (for open tickets) or the hours between the date_logged and the date_closed (for closed tickets) based on the service hours of the department assigned to the ticket.
Public holidays have to be included.
The service hours of the assigned department are saved in the same table as the ticket. The table looks something like this:
incident_ref | department | date_logged | date_closed | sla_mon_start | sla_mon_end | sla_tue_start | sla_tue_end | sla_wed_start | sla_wed_end | sla_thr_start | sla_thr_end | sla_fri_start | sla_fri_end | sla_sat_start | sla_sat_end | sla_sun_start | sla_sun_end |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1660565 | A | 06.01.21 11:30:52 | 01.01.01 07:30:00 | 01.01.01 16:45:00 | 01.01.01 07:30:00 | 01.01.01 16:45 | 01.01.01 07:30:00 | 01.01.01 16:45:00 | 01.01.01 07:30:00 | 01.01.01 16:45:00 | 01.01.01 07:30:00 | 01.01.01 13:00:00 | 01.01.01 00:00:00 | 01.01.01 00:00:00 | 01.01.01 00:00:00 | 01.01.01 00:00:00 | |
1660567 | B | 13.01.21 09:14:16 | 01.01.01 07:00:00 | 01.01.01 16:30:00 | 01.01.01 07:00:00 | 01.01.01 16:30:00 | 01.01.01 07:00:00 | 01.01.01 16:30:00 | 01.01.01 07:00:00 | 01.01.01 16:30:00 | 01.01.01 07:00:00 | 01.01.01 16:30:00 | 01.01.01 07:00:00 | 01.01.01 15:00:00 | 01.01.01 00:00:00 | 01.01.01 00:00:00 | |
1660558 | C | 31.12.20 07:04:46 | 31.12.20 07:36:59 | 01.01.01 07:00:00 | 01.01.01 16:30:00 | 01.01.01 07:00:00 | 01.01.01 16:30:00 | 01.01.01 07:00:00 | 01.01.01 16:30:00 | 01.01.01 07:00:00 | 01.01.01 16:30:00 | 01.01.01 07:00:00 | 01.01.01 16:30:00 | 01.01.01 07:00:00 | 01.01.01 15:00:00 | 01.01.01 00:00:00 | 01.01.01 00:00:00 |
3456789 | D | 01.01.21 09:41:00 | 04.01.21 08:21:00 | 01.01.01 08:00:00 | 01.01.01 15:00:00 | 01.01.01 08:00:00 | 01.01.01 15:00:00 | 01.01.01 08:00:00 | 01.01.01 15:00:00 | 01.01.01 08:00:00 | 01.01.01 15:00:00 | 01.01.01 08:00:00 | 01.01.01 13:00:00 | 01.01.01 00:00:00 | 01.01.01 00:00:00 | 01.01.01 00:00:00 | 01.01.01 00:00:00 |
0123456 | D | 02.01.21 13:12:00 | ... | ... | ... | ... | ... |
I only have the permission to read on this database, so I'm not allowed to alter existing tables or create new ones.
Based on an answer I got on a previous question of mine, I tried to solve it like shown in the following, but this way I only get the error "date+date not allowed". I haven't tried to include public holidays yet, because the rest already didn't work.
SELECT incident_ref,
date_logged,
Inc_close_date,
TO_CHAR( FLOOR( service_time_seconds / 60 / 60 ), 'FM99990' )
|| ':'
|| TO_CHAR( MOD( FLOOR( service_time_seconds / 60 ), 60 ), 'FM00' )
|| ':'
|| TO_CHAR( MOD( service_time_seconds, 60 ), 'FM00' )
AS "service time [hh:mm]"
FROM (
SELECT inc.incident_ref,
inc.date_logged,
inc.Inc_close_date,
ROUND(
(
-- Calculate the full weeks difference from the start of ISO weeks.
(
TRUNC( COALESCE( Inc_close_date, SYSDATE ), 'IW' )
- TRUNC( date_logged, 'IW' )
) * ( (24*(sla_mon_end-sla_mon_start))
+ (24*(sla_tue_end-sla_tue_start))
+ (24*(sla_wed_end-sla_wed_start))
+ (24*(sla_thr_end-sla_thr_start))
+ (24*(sla_fri_end-sla_fri_start))
+ (24*(sla_sat_end-sla_sat_start))
+ (24*(sla_sun_end-sla_sun_start) )) / (7*24)
-- Add the hours for the full days for the final week.
+ DECODE(
TRUNC( COALESCE( Inc_close_date, SYSDATE ) )
- TRUNC( COALESCE( Inc_close_date, SYSDATE ), 'IW' ),
0, 0.0,
1, (24*(sla_mon_end-sla_mon_start)),
2, (24*(sla_mon_end-sla_mon_start)) + 24*(sla_wed_end-sla_tue_start),
3, (24*(sla_mon_end-sla_mon_start)) + 24*(sla_wed_end-sla_tue_start) + 24*(sla_wed_end-sla_wed_start),
4, (24*(sla_mon_end-sla_mon_start)) + 24*(sla_wed_end-sla_tue_start) + 24*(sla_wed_end-sla_wed_start) + 24*(sla_thr_end-sla_thr_start),
5, (24*(sla_mon_end-sla_mon_start)) + 24*(sla_wed_end-sla_tue_start) + 24*(sla_wed_end-sla_wed_start) + 24*(sla_thr_end-sla_thr_start) + 24*(sla_fri_end-sla_fri_start),
6, (24*(sla_mon_end-sla_mon_start)) + 24*(sla_wed_end-sla_tue_start) + 24*(sla_wed_end-sla_wed_start) + 24*(sla_thr_end-sla_thr_start) + 24*(sla_fri_end-sla_fri_start) + 24*(sla_sat_end-sla_sat_start)
) / 24
-- Subtract the hours for the full days from the days of the week
-- before the date logged.
- DECODE(
TRUNC( date_logged ) - TRUNC( date_logged, 'IW' ),
0, 0.0,
1, 24*(sla_mon_end-sla_mon_start),
2, 24*(sla_mon_end-sla_mon_start) + 24*(sla_wed_end-sla_tue_start),
3, 24*(sla_mon_end-sla_mon_start) + 24*(sla_wed_end-sla_tue_start) + 24*(sla_wed_end-sla_wed_start),
4, 24*(sla_mon_end-sla_mon_start) + 24*(sla_wed_end-sla_tue_start) + 24*(sla_wed_end-sla_wed_start) + 24*(sla_thr_end-sla_thr_start),
5, 24*(sla_mon_end-sla_mon_start) + 24*(sla_wed_end-sla_tue_start) + 24*(sla_wed_end-sla_wed_start) + 24*(sla_thr_end-sla_thr_start) + 24*(sla_fri_end-sla_fri_start),
6, 24*(sla_mon_end-sla_mon_start) + 24*(sla_wed_end-sla_tue_start) + 24*(sla_wed_end-sla_wed_start) + 24*(sla_thr_end-sla_thr_start) + 24*(sla_fri_end-sla_fri_start) + 24*(sla_sat_end-sla_sat_start)
) / 24
-- Add the hours of the final day
+ COALESCE(
GREATEST(
LEAST(
COALESCE( Inc_close_date, SYSDATE ),
TRUNC( COALESCE( Inc_close_date, SYSDATE ) )
+ DECODE(
TRUNC( COALESCE( Inc_close_date, SYSDATE ) )
- TRUNC( COALESCE( Inc_close_date, SYSDATE ), 'IW' ),
0, sla_mon_end,
1, sla_tue_end,
2, sla_wed_end,
3, sla_thr_end,
4, sla_fri_end,
5, sla_sat_end,
6, sla_sun_end
)
)
-
(
TRUNC( COALESCE( Inc_close_date, SYSDATE ) )
+ DECODE(
TRUNC( COALESCE( Inc_close_date, SYSDATE ) )
- TRUNC( COALESCE( Inc_close_date, SYSDATE ), 'IW' ),
0, sla_mon_start,
1, sla_tue_start,
2, sla_wed_start,
3, sla_thr_start,
4, sla_fri_start,
5, sla_sat_start,
6, sla_sun_start
)
),
0
) / 24,
0
)
-- Subtract the hours of the day before the range starts.
+ COALESCE(
GREATEST(
LEAST(
date_logged,
date_logged
+ DECODE(
TRUNC( COALESCE( Inc_close_date, SYSDATE ) )
- TRUNC( COALESCE( Inc_close_date, SYSDATE ), 'IW' ),
0, sla_mon_end,
1, sla_tue_end,
2, sla_wed_end,
3, sla_thr_end,
4, sla_fri_end,
5, sla_sat_end,
6, sla_sun_end
)
)
-
(
date_logged
+ DECODE(
TRUNC( COALESCE( Inc_close_date, SYSDATE ) )
- TRUNC( COALESCE( Inc_close_date, SYSDATE ), 'IW' ),
0, sla_mon_start,
1, sla_tue_start,
2, sla_wed_start,
3, sla_thr_start,
4, sla_fri_start,
5, sla_sat_start,
6, sla_sun_start
)
),
0
) / 24,
0
)
)
-- Multiply to give seconds rather than fractions of full days.
* 24 * 60 * 60
) AS service_time_seconds
FROM incident inc
);
(The tickets are the same ones as in the table above, if you should wonder about the departments. The current datetime column is just for reference, it isn't needed in the actual result)
incident_ref | date_logged | date_closed | service time [hh:mm] | current datetime |
---|---|---|---|---|
1660565 | 31.12.20 07:15:48 | 131:54 | 22.01.2021 10:09 | |
1660567 | 31.12.20 07:17:56 | 160:21 | 22.01.2021 10:09 | |
1660558 | 31.12.20 07:04:46 | 31.12.20 07:36:59 | 00:32 | 22.01.2021 10:09 |
3456789 | 01.01.21 09:41:00 | 04.01.21 08:21:00 | 00:21 | 22.01.2021 10:09 |
With the last ticket you can see that the assigned department didn't work on new year.
Maybe this would help:
WITH
sample AS -- sample data with DATE_CLOSED defined
(
SELECT DISTINCT
INCIDENT_REF,
DEPARTMENT, SLA_MON_START, SLA_MON_END, SLA_TUE_START, SLA_TUE_END, SLA_WED_START, SLA_WED_END, SLA_THR_START, SLA_THR_END, SLA_FRI_START, SLA_FRI_END, SLA_SAT_START, SLA_SAT_END, SLA_SUN_START, SLA_SUN_END,
DATE_LOGGED,
To_Char(DATE_LOGGED, 'hh:mi') "TIME_LOGGED",
Nvl(DATE_CLOSED, To_Date('01.22.2021 10:09', 'mm.dd.yyyy hh24:mi')) "DATE_CLOSED",
To_Char(Nvl(DATE_CLOSED, To_Date('01.22.2021 10:09', 'mm.dd.yyyy hh24:mi')), 'hh:mi') "TIME_CLOSED"
FROM
SAMPLEDATA s
),
days AS -- generate all the missing dates with the service hours depending on a day of week - calculate effective service time (hours) by date
(
SELECT DISTINCT
INCIDENT_REF "INCIDENT_REF",
DEPARTMENT "DEPARTMENT",
DATE_LOGGED "DATE_LOGGED",
DATE_LOGGED + LEVEL - 1 "WRK_DATE",
CASE
WHEN To_Char(DATE_LOGGED + LEVEL - 1, 'd') = '1' THEN To_Char(SLA_MON_START, 'hh24:mi') || '-' || To_Char(SLA_MON_END, 'hh24:mi')
WHEN To_Char(DATE_LOGGED + LEVEL - 1, 'd') = '2' THEN To_Char(SLA_TUE_START, 'hh24:mi') || '-' || To_Char(SLA_TUE_END, 'hh24:mi')
WHEN To_Char(DATE_LOGGED + LEVEL - 1, 'd') = '3' THEN To_Char(SLA_WED_START, 'hh24:mi') || '-' || To_Char(SLA_WED_END, 'hh24:mi')
WHEN To_Char(DATE_LOGGED + LEVEL - 1, 'd') = '4' THEN To_Char(SLA_THR_START, 'hh24:mi') || '-' || To_Char(SLA_THR_END, 'hh24:mi')
WHEN To_Char(DATE_LOGGED + LEVEL - 1, 'd') = '5' THEN To_Char(SLA_FRI_START, 'hh24:mi') || '-' || To_Char(SLA_FRI_END, 'hh24:mi')
WHEN To_Char(DATE_LOGGED + LEVEL - 1, 'd') = '6' THEN To_Char(SLA_SAT_START, 'hh24:mi') || '-' || To_Char(SLA_SAT_END, 'hh24:mi')
WHEN To_Char(DATE_LOGGED + LEVEL - 1, 'd') = '7' THEN To_Char(SLA_SUN_START, 'hh24:mi') || '-' || To_Char(SLA_SUN_END, 'hh24:mi')
END "SERVICE_HOURS_SPAN",
--
CASE
WHEN To_Char(DATE_LOGGED + LEVEL - 1, 'd') = '1' THEN (SLA_MON_END - SLA_MON_START) * 24
WHEN To_Char(DATE_LOGGED + LEVEL - 1, 'd') = '2' THEN (SLA_TUE_END - SLA_TUE_START) * 24
WHEN To_Char(DATE_LOGGED + LEVEL - 1, 'd') = '3' THEN (SLA_WED_END - SLA_WED_START) * 24
WHEN To_Char(DATE_LOGGED + LEVEL - 1, 'd') = '4' THEN (SLA_THR_END - SLA_THR_START) * 24
WHEN To_Char(DATE_LOGGED + LEVEL - 1, 'd') = '5' THEN (SLA_FRI_END - SLA_FRI_START) * 24
WHEN To_Char(DATE_LOGGED + LEVEL - 1, 'd') = '6' THEN (SLA_SAT_END - SLA_SAT_START) * 24
WHEN To_Char(DATE_LOGGED + LEVEL - 1, 'd') = '7' THEN (SLA_SUN_END - SLA_SUN_START) * 24
END "SCHEDULED_SERVICE_HOURS",
--
CASE
WHEN TRUNC(DATE_LOGGED, 'dd') = TRUNC(DATE_LOGGED + LEVEL - 1, 'dd') And To_Char(DATE_LOGGED + LEVEL - 1, 'd') = '1' And TRUNC(DATE_LOGGED, 'dd') <> TRUNC(Nvl(DATE_CLOSED, To_Date('01.22.2021', 'mm.dd.yyyy')), 'dd') THEN (SLA_MON_END - To_Date(To_Char(SLA_MON_END, 'mm.dd.yyyy') || ' ' || TIME_LOGGED, 'mm.dd.yyyy hh24:mi')) * 24
WHEN TRUNC(DATE_LOGGED, 'dd') = TRUNC(DATE_LOGGED + LEVEL - 1, 'dd') And To_Char(DATE_LOGGED + LEVEL - 1, 'd') = '2' And TRUNC(DATE_LOGGED, 'dd') <> TRUNC(Nvl(DATE_CLOSED, To_Date('01.22.2021', 'mm.dd.yyyy')), 'dd') THEN (SLA_TUE_END - To_Date(To_Char(SLA_TUE_END, 'mm.dd.yyyy') || ' ' || TIME_LOGGED, 'mm.dd.yyyy hh24:mi')) * 24
WHEN TRUNC(DATE_LOGGED, 'dd') = TRUNC(DATE_LOGGED + LEVEL - 1, 'dd') And To_Char(DATE_LOGGED + LEVEL - 1, 'd') = '3' And TRUNC(DATE_LOGGED, 'dd') <> TRUNC(Nvl(DATE_CLOSED, To_Date('01.22.2021', 'mm.dd.yyyy')), 'dd') THEN (SLA_WED_END - To_Date(To_Char(SLA_WED_END, 'mm.dd.yyyy') || ' ' || TIME_LOGGED, 'mm.dd.yyyy hh24:mi')) * 24
WHEN TRUNC(DATE_LOGGED, 'dd') = TRUNC(DATE_LOGGED + LEVEL - 1, 'dd') And To_Char(DATE_LOGGED + LEVEL - 1, 'd') = '4' And TRUNC(DATE_LOGGED, 'dd') <> TRUNC(Nvl(DATE_CLOSED, To_Date('01.22.2021', 'mm.dd.yyyy')), 'dd') THEN (SLA_THR_END - To_Date(To_Char(SLA_THR_END, 'mm.dd.yyyy') || ' ' || TIME_LOGGED, 'mm.dd.yyyy hh24:mi')) * 24
WHEN TRUNC(DATE_LOGGED, 'dd') = TRUNC(DATE_LOGGED + LEVEL - 1, 'dd') And To_Char(DATE_LOGGED + LEVEL - 1, 'd') = '5' And TRUNC(DATE_LOGGED, 'dd') <> TRUNC(Nvl(DATE_CLOSED, To_Date('01.22.2021', 'mm.dd.yyyy')), 'dd') THEN (SLA_FRI_END - To_Date(To_Char(SLA_FRI_END, 'mm.dd.yyyy') || ' ' || TIME_LOGGED, 'mm.dd.yyyy hh24:mi')) * 24
WHEN TRUNC(DATE_LOGGED, 'dd') = TRUNC(DATE_LOGGED + LEVEL - 1, 'dd') And To_Char(DATE_LOGGED + LEVEL - 1, 'd') = '6' And TRUNC(DATE_LOGGED, 'dd') <> TRUNC(Nvl(DATE_CLOSED, To_Date('01.22.2021', 'mm.dd.yyyy')), 'dd') THEN (SLA_SAT_END - To_Date(To_Char(SLA_SAT_END, 'mm.dd.yyyy') || ' ' || TIME_LOGGED, 'mm.dd.yyyy hh24:mi')) * 24
WHEN TRUNC(DATE_LOGGED, 'dd') = TRUNC(DATE_LOGGED + LEVEL - 1, 'dd') And To_Char(DATE_LOGGED + LEVEL - 1, 'd') = '7' And TRUNC(DATE_LOGGED, 'dd') <> TRUNC(Nvl(DATE_CLOSED, To_Date('01.22.2021', 'mm.dd.yyyy')), 'dd') THEN (SLA_SUN_END - To_Date(To_Char(SLA_SUN_END, 'mm.dd.yyyy') || ' ' || TIME_LOGGED, 'mm.dd.yyyy hh24:mi')) * 24
--
WHEN TRUNC(DATE_LOGGED, 'dd') = TRUNC(Nvl(DATE_CLOSED, To_Date('01.22.2021', 'mm.dd.yyyy')), 'dd') THEN (DATE_CLOSED - DATE_LOGGED) * 24
ELSE
CASE
WHEN To_Char(DATE_LOGGED + LEVEL - 1, 'd') = '1' THEN (SLA_MON_END - SLA_MON_START) * 24
WHEN To_Char(DATE_LOGGED + LEVEL - 1, 'd') = '2' THEN (SLA_TUE_END - SLA_TUE_START) * 24
WHEN To_Char(DATE_LOGGED + LEVEL - 1, 'd') = '3' THEN (SLA_WED_END - SLA_WED_START) * 24
WHEN To_Char(DATE_LOGGED + LEVEL - 1, 'd') = '4' THEN (SLA_THR_END - SLA_THR_START) * 24
WHEN To_Char(DATE_LOGGED + LEVEL - 1, 'd') = '5' THEN (SLA_FRI_END - SLA_FRI_START) * 24
WHEN To_Char(DATE_LOGGED + LEVEL - 1, 'd') = '6' THEN (SLA_SAT_END - SLA_SAT_START) * 24
WHEN To_Char(DATE_LOGGED + LEVEL - 1, 'd') = '7' THEN (SLA_SUN_END - SLA_SUN_START) * 24
END
END "EFF_SERVICE_HOURS",
--
DATE_CLOSED "DATE_CLOSED"
FROM
sample
WHERE
TRUNC(DATE_LOGGED, 'dd') <= TRUNC(Nvl(DATE_CLOSED, To_Date('01.22.2021 10:09', 'mm.dd.yyyy hh:mi')), 'dd')
CONNECT BY
DATE_LOGGED + LEVEL - 1 <= DATE_CLOSED
ORDER BY
DEPARTMENT, DATE_LOGGED + LEVEL - 1
)
SELECT -- Get total service time as hh24:mi
INCIDENT_REF "INCIDENT_REF",
DEPARTMENT "DEPARTMENT",
To_Char(DATE_LOGGED, 'MON-dd-yyyy hh24:mi') "DATE_LOGGED",
To_Char(DATE_CLOSED, 'MON-dd-yyyy hh24:mi') "DATE_CLOSED",
LPAD(FLOOR(Sum(EFF_SERVICE_HOURS * 60) / 60), 2, '0') || ':' || LPAD(Round((Sum(EFF_SERVICE_HOURS) - FLOOR(Sum(EFF_SERVICE_HOURS * 60) / 60)) * 60, 0), 2, '0') "TOTAL_SERVICE_TIME"
FROM
days
GROUP BY
INCIDENT_REF,
DEPARTMENT,
DATE_LOGGED,
DATE_CLOSED
ORDER BY
DEPARTMENT,
INCIDENT_REF
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.