Oracle query to Exclude weekends, and 6PM to 9PM

独自空忆成欢 提交于 2021-01-29 11:03:34

问题


I am trying to achieve a query that returns the time difference between two dates excluding weekends(Saturday and Sunday) and excluding time (6 pm-9 am). For now, I have a function that is excluding the weekends, But I am unable to exclude time from the query. Can anyone help with this? The article from which I take help is this

CREATE OR REPLACE FUNCTION get_bus_minutes_between(

                                   p_start_date DATE,

                                   p_end_date DATE

                                  )

    RETURN NUMBER
    DETERMINISTIC -- ***** Can't hurt
    IS
        days_diff     NUMBER  := 0;
        end_date      DATE    := p_end_date;
        minutes_diff  NUMBER;
        start_date    DATE    := p_start_date;
        weeks_diff    NUMBER;
BEGIN
    IF  start_date <= end_date
    THEN
        --  Move start_date and end_date away from weekends
        IF  start_date > TRUNC (start_date, 'IW') + 5
        THEN     -- Use next Monday for start_date
            start_date := TRUNC (start_date, 'IW') + 7;
        END IF;

        IF  end_date > TRUNC (end_date, 'IW') + 5
        THEN     -- Use Friday quitting time
            end_date := TRUNC (end_date, 'IW') + 4 + (16.5 / 24);
        END IF;

       -- Move start_date into the same weeek as end_date
       -- (Remember how many weeks we had to move it)
       weeks_diff := ( TRUNC (end_date,   'IW')
                     - TRUNC (start_date, 'IW')
                     ) / 7;
       IF  weeks_diff > 0
       THEN
           start_date := start_date + (7 * weeks_diff);
       END IF;

       -- Make start_date the same day as end_date
       -- (Remember how many days we had to move it)
       days_diff := TRUNC (end_date) - TRUNC (start_date);
       IF  days_diff > 0
       THEN
           start_date := start_date + days_diff;
       END IF;

       -- Move start_date up to starting time
       start_date := GREATEST ( start_date
                              , TRUNC (start_date) + (8.75 / 24)
                              );

       -- Move end_date back to quitting time
       end_date := LEAST ( end_date
                         , TRUNC (end_date) + ( CASE
                                                    WHEN  TO_CHAR ( end_date
                                                                  , 'DY'
                                                                  , 'NLS_DATE_LANGUAGE=ENGLISH'
                                                                  ) = 'FRI'
                                                    THEN  16.5
                                                    ELSE  17
                                                END
                                              / 24
                                              )
                         );

         minutes_diff := ( GREATEST ( 0
                                    , end_date - start_date
                                    )
                         * 24 * 60
                         )
                     +  (days_diff * 495)     --  495 minutes per full day (Mon.-Thu.)
                     +  (weeks_diff * 2445);  -- 2445 minutes per full week
    ELSIF  start_date > end_date
    THEN
        minutes_diff := -get_bus_minutes_between (end_date, start_date);
    ELSE    -- One of the arguments was NULL
        minutes_diff := NULL;
    END IF;

   RETURN  ROUND(minutes_diff);
END  get_bus_minutes_between;

回答1:


You can directly calculate the difference in days (adapted from my answer here):

SELECT start_date,
       end_date,
       ROUND(
         (
           -- Calculate the full weeks difference from the start of ISO weeks.
           ( TRUNC( end_date, 'IW' ) - TRUNC( start_date, 'IW' ) ) * (9/24) * (5/7)
           -- Add the full days for the final week.
           + LEAST( TRUNC( end_date ) - TRUNC( end_date, 'IW' ), 5 ) * (9/24)
           -- Subtract the full days from the days of the week before the start date.
           - LEAST( TRUNC( start_date ) - TRUNC( start_date, 'IW' ), 5 ) * (9/24)
           -- Add the hours of the final day
           + LEAST( GREATEST( end_date - TRUNC( end_date ) - 9/24, 0 ), 9/24 )
           -- Subtract the hours of the day before the range starts.
           - LEAST( GREATEST( start_date - TRUNC( start_date ) - 9/24, 0 ), 9/24 )
         )
         -- Multiply to give minutes rather than fractions of full days.
         * 24 * 60
       ) AS work_day_mins_diff
FROM   table_name;

Which, for the sample data:

CREATE TABLE table_name ( start_date, end_date ) AS
SELECT DATE '2020-12-30' + INTERVAL '00' HOUR, DATE '2020-12-30' + INTERVAL '12' HOUR FROM DUAL UNION ALL
SELECT DATE '2020-12-30' + INTERVAL '18' HOUR, DATE '2020-12-30' + INTERVAL '20' HOUR FROM DUAL UNION ALL
SELECT DATE '2020-12-30' + INTERVAL '17:30' HOUR TO MINUTE, DATE '2020-12-30' + INTERVAL '21:30' HOUR TO MINUTE FROM DUAL UNION ALL
SELECT DATE '2021-01-01' + INTERVAL '00' HOUR, DATE '2021-01-04' + INTERVAL '00' HOUR FROM DUAL UNION ALL
SELECT DATE '2021-01-02' + INTERVAL '00' HOUR, DATE '2021-01-04' + INTERVAL '00' HOUR FROM DUAL UNION ALL
SELECT DATE '2020-12-28' + INTERVAL '00' HOUR, DATE '2021-01-04' + INTERVAL '00' HOUR FROM DUAL UNION ALL
SELECT DATE '2020-12-28' + INTERVAL '00' HOUR, DATE '2020-12-29' + INTERVAL '00' HOUR FROM DUAL;

Outputs:

(Using ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS (DY)';)

START_DATE                | END_DATE                  | WORK_DAY_MINS_DIFF
:------------------------ | :------------------------ | -----------------:
2020-12-30 00:00:00 (WED) | 2020-12-30 12:00:00 (WED) |                180
2020-12-30 18:00:00 (WED) | 2020-12-30 20:00:00 (WED) |                  0
2020-12-30 17:30:00 (WED) | 2020-12-30 21:30:00 (WED) |                 30
2021-01-01 00:00:00 (FRI) | 2021-01-04 00:00:00 (MON) |                540
2021-01-02 00:00:00 (SAT) | 2021-01-04 00:00:00 (MON) |                  0
2020-12-28 00:00:00 (MON) | 2021-01-04 00:00:00 (MON) |               2700
2020-12-28 00:00:00 (MON) | 2020-12-29 00:00:00 (TUE) |                540

db<>fiddle here



来源:https://stackoverflow.com/questions/65513591/oracle-query-to-exclude-weekends-and-6pm-to-9pm

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!