sql >> データベース >  >> RDS >> Oracle

Oracleで非稼働時間をなくす方法

    正しく理解できれば、午前10時前と午後7時以降の時間を除いた開始日と終了日の差を計算する必要があります。

    これがサンプルクエリとSQLフィドルです。

    SELECT start_time,
           finish_time,
           interval_time,
           EXTRACT (HOUR FROM interval_time), --extract the hours,mins and seconds from the interval
           EXTRACT (MINUTE FROM interval_time),
           EXTRACT (SECOND FROM interval_time)
      FROM (SELECT start_time,
                   finish_time,
                   NUMTODSINTERVAL (
                        CASE
                           WHEN finish_time - TRUNC (finish_time) > (19 / 24) --if finish time is after 7pm
                           THEN
                              TRUNC (finish_time) + (19 / 24)      --set it to 7pm
                           ELSE
                              finish_time      --else set it to actual finish time
                        END
                      - CASE
                           WHEN start_time - TRUNC (start_time) < (10 / 24) --if start time is before 10 am
                           THEN
                              TRUNC (start_time) + (10 / 24)    --set it to 10 am.
                           ELSE
                              start_time    --else set it to the actual start time
                        END,
                      'day') --subtract the both and convert the resulting day to interval
                      interval_time
              FROM timings);
    

    私がやったことは、

    • 開始時刻が午前10時より前で、終了時刻が午後7時以降であるかどうかを確認します。その場合は、時刻を午前10時と午後7時に設定します。
    • 次に、日付を減算し、結果の日数を間隔タイプに変換します。
    • 次に、間隔から時間、分、秒を抽出します。

    注: このクエリは、両方の日付が同じ日になり、両方が午前10時前または午後7時以降ではないことを前提としています。

    更新: 休日を除外すると、クエリが複雑になります。 3つの関数を記述し、これらの関数をクエリで使用することをお勧めします。

    最初の機能:

    FUNCTION modify_start_time (p_in_dte DATE) RETURN DATE
    ----------------------------------
    IF p_in_dte - TRUNC (p_in_dte) < (10 / 24)
    THEN
       RETURN TRUNC (p_in_dte) + (10 / 24);
    ELSIF p_in_dte - TRUNC (p_in_dte) > (19 / 24)
    THEN
       RETURN TRUNC (p_in_dte) + 1 + (10 / 24);
    ELSE
       RETURN p_in_dte;
    END IF;
    

    開始時間が勤務時間外の場合は、開始時間を次に近い開始時間に変更します。

    2番目の機能:

    FUNCTION modify_finish_time (p_in_dte DATE) RETURN DATE
    ----------------------------------
    IF p_in_dte - TRUNC (p_in_dte) > (19 / 24)
    THEN
       RETURN TRUNC (p_in_dte) + (19 / 24);
    ELSIF p_in_dte - TRUNC (p_in_dte) < (10 / 24)
    THEN
       RETURN TRUNC (p_in_dte) - 1 + (19 / 24);
    ELSE
       RETURN p_in_dte;
    END IF;
    

    終了時間が勤務時間外の場合は、前の最も近い終了時間に変更します。

    3番目の機能:

    FUNCTION get_days_to_exclude (p_in_start_date     DATE,
                                  p_in_finish_date    DATE) RETURN NUMBER
    --------------------------------------------------------
    WITH cte --get all days between start and finish date
         AS (    SELECT p_in_start_date + LEVEL - 1 dte
                   FROM DUAL
             CONNECT BY LEVEL <= p_in_finish_date + 1 - p_in_starT_date)
    SELECT COUNT (1) * 9 / 24    --mutiply the days with work hours in a day
      INTO l_num_holidays
      FROM cte
     WHERE    TO_CHAR (dte, 'dy') = 'sun'    --find the count of sundays
           OR dte IN     --fins the count of holidays, assuming leaves are stored in separate table
                 (SELECT leave_date  
                    FROM leaves
                   WHERE leave_date BETWEEN p_in_start_date
                                        AND p_in_finish_date);
    
    l_num_holidays :=
       l_num_holidays + ( (p_in_finish_date - p_in_start_date) * (15 / 24)); --also, if the dates span more than a day find the non working hours.
    
    RETURN l_num_holidays;
    

    この関数は、期間の計算中に除外される日数を検出します。

    したがって、最終的なクエリは次のようになります。

    SELECT start_time,
           finish_time,
           CASE
              WHEN work_duration < 0 THEN NUMTODSINTERVAL (0, 'day')
              ELSE NUMTODSINTERVAL (work_duration, 'day')
           END
      FROM (SELECT start_time, finish_time,
                   --modify_start_time (start_time), modify_finish_time (finish_time),
                     modify_finish_time (finish_time)
                   - modify_start_time (start_time)
                   - get_days_to_exclude (
                        TRUNC (modify_start_time (start_time)),
                        TRUNC (modify_finish_time (finish_time)))
                      work_duration
              FROM timings);
    

    期間が0未満の場合は、0に設定して無視します。



    1. ClusterControlを使用してデータベースフェイルオーバーを自動化する方法

    2. ORA-03113:通信チャネルのファイルの終わり

    3. PostgreSQLマルチクラウドクラスターの展開

    4. SELECTステートメントの前の行の値にアクセスする方法はありますか?