Oracle
 sql >> Baza danych >  >> RDS >> Oracle

Jak wyeliminować godziny wolne od pracy w Oracle

Jeśli dobrze rozumiem, chcesz obliczyć różnicę między datą początkową i końcową, z wyłączeniem czasu przed 10 rano i po 19:00.

Oto przykładowe zapytanie i skrzypce 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);

To, co zrobiłem, to

  • Sprawdź, czy godzina rozpoczęcia jest przed godziną 10:00, a godzina zakończenia po godzinie 19:00. Jeśli tak, ustaw godzinę na 10:00 i 19:00.
  • Następnie odejmij daty i przekonwertuj otrzymane dni na typ interwału.
  • Następnie wyodrębnij godziny, minuty i sekundy z interwału.

Uwaga: To zapytanie zakłada, że ​​obie daty przypadają tego samego dnia i obie nie są przed 10 rano ani po 19:00.

AKTUALIZACJA: Aby wykluczyć święta, zapytanie stanie się skomplikowane. Proponuję napisać trzy funkcje i użyć ich w zapytaniu.

Pierwsza funkcja:

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;

Jeśli czas rozpoczęcia jest poza godzinami pracy, zmień czas rozpoczęcia na najbliższy najbliższy czas rozpoczęcia.

Druga funkcja:

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;

Jeśli czas zakończenia jest poza godzinami pracy, zmień go na poprzedni najbliższy czas zakończenia.

3. funkcja:

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;

Ta funkcja znajduje liczbę dni do wykluczenia podczas obliczania czasu trwania.

Tak więc ostatnie zapytanie powinno wyglądać mniej więcej tak,

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);

Jeśli czas trwania jest krótszy niż 0, zignoruj ​​go, ustawiając go na 0.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak zintegrować Oracle i Kafka

  2. Jak przekazać argumenty do skryptu PL/SQL w wierszu poleceń za pomocą SQLPLUS?

  3. [01000][unixODBC][Menedżer sterowników] Nie można otworzyć biblioteki „/usr/local/easysoft/oracle/InstantClient112/lib/libsqora.so”:nie znaleziono pliku

  4. Nie można skompilować GI 12.1.0.2 i błędu segmentacji

  5. Korzystanie z Oracle JDeveloper 12c z Oracle Database 12c na platformie Oracle Cloud, część 3