I would be very grateful if you could help me with this problem.
I have this results of a Oracle SQL query, are about a night shift schedule.
start_day_hours are the total worked hours between the shift start_date and the midnight. end_day_hours are the total worked hours between the midnight en the end of the shift.
start midnight end start_day_hours end_day_hours
02/10/17 21:33 02/10/17 23:59 03/10/17 00:42 2,43 0,71
03/10/17 21:34 03/10/17 23:59 04/10/17 00:19 2,42 0,32
04/10/17 21:59 04/10/17 23:59 05/10/17 55:36 2,00 0,92
16/10/17 21:59 16/10/17 23:59 17/10/17 00:01 2,00 0,01
18/10/17 22:50 18/10/17 23:59 19/10/17 00:25 1,16 0,42
19/10/17 22:19 19/10/17 23:59 20/10/17 01:00 1,67 1,01
I need the sum of start_day_hours and end_day_hours by day, something like:
day total_hours
02/10/17 2,43 (2,43)
03/10/17 3,13 (0.71+2,42)
04/10/17 2,32 (0.32+2.00)
05/10/17 0,92 (0,92)
16/10/17 2,00 (2,00)
17/10/17 0,01 (0,01)
18/10/17 1,16 (1,16)
19/10/17 2,51 (0.42+1.67)
20/10/17 1,01 (1,01)
Thanks a lot for your help!
Oracle 11g R2 Schema Setup :
CREATE TABLE shift (
"start" DATE,
"end" DATE
);
INSERT INTO shift
SELECT TIMESTAMP '2017-10-02 21:33:00', TIMESTAMP '2017-10-03 00:42:00' FROM DUAL UNION ALL
SELECT TIMESTAMP '2017-10-03 21:34:00', TIMESTAMP '2017-10-04 00:19:00' FROM DUAL UNION ALL
SELECT TIMESTAMP '2017-10-04 21:59:00', TIMESTAMP '2017-10-05 00:55:00' FROM DUAL UNION ALL
SELECT TIMESTAMP '2017-10-16 21:59:00', TIMESTAMP '2017-10-17 00:01:00' FROM DUAL UNION ALL
SELECT TIMESTAMP '2017-10-18 22:50:00', TIMESTAMP '2017-10-19 00:25:00' FROM DUAL UNION ALL
SELECT TIMESTAMP '2017-10-19 22:19:00', TIMESTAMP '2017-10-20 01:00:00' FROM DUAL;
Query 1 :
Use a row generator to get each day between the earliest start
and the latest end
and then join it to the original table when the day overlaps the shift and aggregate those overlaps:
WITH days ( dt ) AS (
SELECT min_dt + LEVEL - 1
FROM (
SELECT TRUNC( MIN( "start" ) ) AS min_dt,
TRUNC( MAX( "end" ) ) AS max_dt
FROM shift
)
CONNECT BY min_dt + LEVEL - 1 <= max_dt
)
SELECT dt,
SUM(
LEAST( "end", dt + INTERVAL '1' DAY )
- GREATEST( "start", dt )
) * 24 AS hours_worked
FROM shift s
INNER JOIN days d
ON ( s."start" < d.dt + INTERVAL '1' DAY
AND s."end" > d.dt )
GROUP BY dt
ORDER BY dt
Results :
| DT | HOURS_WORKED |
|----------------------|----------------------|
| 2017-10-02T00:00:00Z | 2.45 |
| 2017-10-03T00:00:00Z | 3.1333333333333333 |
| 2017-10-04T00:00:00Z | 2.3333333333333335 |
| 2017-10-05T00:00:00Z | 0.9166666666666666 |
| 2017-10-16T00:00:00Z | 2.0166666666666666 |
| 2017-10-17T00:00:00Z | 0.016666666666666666 |
| 2017-10-18T00:00:00Z | 1.1666666666666667 |
| 2017-10-19T00:00:00Z | 2.1 |
| 2017-10-20T00:00:00Z | 1 |
One simple way could be to union start/end date
into 1 column and start_hours/end_hours
into other column, trunc
date
column, group by
date and calculate sum
of hours
column as below.
SELECT date1 AS DAY,
sum(hours) AS total_hours
FROM
(SELECT trunc(start1) AS date1,
start_day_hours AS hours
FROM t1
UNION ALL
SELECT trunc(end1),
end_day_hours
FROM t1 ) t
GROUP BY date1
ORDER BY date1;
Result:
DAY TOTAL_HOURS
---------------------------------
02.10.2017 00:00:00 2,43
03.10.2017 00:00:00 3,13
04.10.2017 00:00:00 2,32
05.10.2017 00:00:00 0,92
16.10.2017 00:00:00 2
17.10.2017 00:00:00 0,01
18.10.2017 00:00:00 1,16
19.10.2017 00:00:00 2,09
20.10.2017 00:00:00 1,01
Thanks a lot for your help @MT0. Finally I have done this:
SELECT dt,
NVL(SUM(
LEAST( SIXTY, dt + INTERVAL '1' DAY )
- GREATEST( ZERO, dt )
) * 24, 0.0) AS hours_worked
FROM shitf s
RIGHT JOIN
(SELECT TO_DATE('2017-10-01 00:00:00', 'YYYY/MM/DD HH24:MI:SS')+LEVEL-1 AS dt
FROM DUAL CONNECT BY LEVEL <= TO_CHAR(LAST_DAY(TO_DATE('2017-10-01 00:00:00', 'YYYY/MM/DD HH24:MI:SS')),'DD')) d
ON (s.ZERO < d.dt + INTERVAL '1' DAY
AND s.SIXTY > d.dt )
GROUP dt
ORDER dt
SELECT T1.START_DATE,nvl(T1.START_DAY_HOURS,0) + nvl(T2.END_DAY_HOURS,0) TOTAL_HOURS
FROM
(SELECT TRUNC(START) START_DATE,sum(nvl(START_DAY_HOURS,0)) START_DAY_HOURS FROM YOUR_TABLE GROUP BY TRUNC(START)) T1
LEFT JOIN (SELECT TRUNC(END) END_DATE,SUM(nvl(END_DAY_HOURS,0)) END_DAY_HOURS FROM YOUR_TABLE GROUP BY TRUNC(END)) T2
ON T1.START_DATE = T2.END_DATE
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.