Oracle
 sql >> Base de données >  >> RDS >> Oracle

Calculer la différence de temps en SQL avec des décalages

Utilisez une clause de factorisation de sous-requête récursive pour générer chaque jour dans vos plages horaires, puis corrélez cela avec vos quarts de travail pour limiter le temps de chaque jour dans les heures de quart, puis agrégez pour obtenir le total :

Configuration d'Oracle 18 :

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;

Requête 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;

Résultat :

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