Använd en rekursiv sub-query factoring-klausul för att generera varje dag inom dina tidsintervall och sedan korrelera det med dina skift för att begränsa tiden för varje dag att vara inom skifttimmarna och sedan aggregera för att få summan:
Oracle 18-installation :
CREATE TABLE times ( start_date, End_Date ) AS
SELECT DATE '2017-02-21' + INTERVAL '07:52:32' HOUR TO SECOND,
DATE '2017-02-22' + INTERVAL '09:56:32' HOUR TO SECOND
FROM DUAL
UNION ALL
SELECT DATE '2017-02-21' + INTERVAL '09:52:32' HOUR TO SECOND,
DATE '2017-02-23' + INTERVAL '17:52:32' HOUR TO SECOND
FROM DUAL;
CREATE TABLE weekly_shifts ( shift_day, Start_Time, End_Time ) AS
SELECT 'MON', INTERVAL '09:00' HOUR TO MINUTE, INTERVAL '18:00' HOUR TO MINUTE FROM DUAL UNION ALL
SELECT 'TUE', INTERVAL '10:00' HOUR TO MINUTE, INTERVAL '19:00' HOUR TO MINUTE FROM DUAL UNION ALL
SELECT 'WED', INTERVAL '09:00' HOUR TO MINUTE, INTERVAL '18:00' HOUR TO MINUTE FROM DUAL UNION ALL
SELECT 'THU', INTERVAL '10:00' HOUR TO MINUTE, INTERVAL '19:00' HOUR TO MINUTE FROM DUAL UNION ALL
SELECT 'FRI', INTERVAL '09:00' HOUR TO MINUTE, INTERVAL '18:00' HOUR TO MINUTE FROM DUAL;
Fråga 1 :
WITH days ( id, start_date, day_start, day_end, end_date ) AS (
SELECT ROWNUM,
start_date,
start_date,
LEAST( TRUNC( start_date ) + INTERVAL '1' DAY, end_date ),
end_date
FROM times
UNION ALL
SELECT id,
start_date,
day_end,
LEAST( day_end + INTERVAL '1' DAY, end_date ),
end_date
FROM days
WHERE day_end < end_date
)
SELECT start_date,
end_date,
SUM( shift_end - shift_start ) AS days_worked_on_shift
FROM (
SELECT ID,
start_date,
end_date,
GREATEST( day_start, TRUNC( day_start ) + start_time ) AS shift_start,
LEAST( day_end, TRUNC( day_start ) + end_time ) AS shift_end
FROM days d
INNER JOIN
weekly_shifts w
ON ( TO_CHAR( d.day_start, 'DY' ) = w.shift_day )
)
GROUP BY id, start_date, end_date;
Resultat :
START_DATE END_DATE DAYS_WORKED_ON_SHIFT
------------------- ------------------- --------------------
2017-02-21 07:52:32 2017-02-22 09:56:32 0.414259259259259259
2017-02-21 09:52:32 2017-02-23 17:52:32 1.078148148148148148