2011-11-01 1 views
2

이므로 오후 6 시부 터 오전 8 시까 지의 간격을 무시하고 두 날짜의 차이 (초)를 알아야합니다.오라클 데이터베이스를 사용하여 밤을 무시한 SQL 날짜 차이가

예를 들어, 01.11.2011 1pm과 03.11.2011 1pm의 차이는 20 시간 (또는 각각 72000 초)입니다. 나는 또한 주말과 휴일을 무시할 필요가 있지만, 이미 PLSQL 함수를 가지고있다.

미리 감사드립니다.

감사합니다, 알렉스


한편 솔직히 매우 정교한 아니라 작업 수행하는 솔루션을 나 자신, 함께했다
편집 : 또한

CREATE OR REPLACE FUNCTION "GET_WORKTIME" 
(
    startdate_in in date, 
    enddate_in in date 
) 
RETURN NUMBER 
AS 
    days_between number(4); 
    duration number; 
    end_of_first_day date; 
    start_of_last_day date; 
    startdate date; 
    enddate date; 
    weekday number(1); 
    temp_date date; 
    holidays day_array; 
    is_holiday boolean; 
BEGIN 
    duration  := 0; 
    startdate := startdate_in; 
    enddate  := enddate_in; 

IF (startdate IS NULL OR enddate IS NULL OR startdate >= enddate) THEN 
    RETURN 0; 
END IF; 

days_between := trunc(enddate) - trunc(startdate); 

end_of_first_day := to_date(concat(to_char(startdate, 'dd.mm.yyyy'), ' 18:00:00'), 'dd.mm.yyyy hh24:mi:ss'); 
start_of_last_day := to_date(concat(to_char(enddate, 'dd.mm.yyyy'), ' 08:00:00'), 'dd.mm.yyyy hh24:mi:ss'); 

temp_date := startdate; 

FOR i IN 0..days_between LOOP 
    -- if it is the first day, just calculate the time until the end of that day 
    IF i = 0 THEN 
     duration := duration + greatest((end_of_first_day - startdate), 0) * 24 * 3600; 

    -- if it is the last day, just calculate the time until that point in time 
    ELSIF i = days_between THEN 
     duration := duration + greatest((enddate - start_of_last_day), 0) * 24 * 3600;    

    -- for every other day, simply add 10 hours (6pm - 8am) if it is neither 
    -- saturday or sunday nor a holiday 
    ELSE 
     weekday := to_number(to_char(temp_date, 'D')); 
     is_holiday := false; 

     -- weekend? 
     IF (NOT weekday IN (6,7)) THEN 

      -- holiday? 
      FOR j IN extract(year FROM startdate)..extract(year FROM enddate) LOOP 
       holidays := get_holidays_for_year(j); 

       FOR k IN 1..holidays.count LOOP 
        IF (holidays(k) = trunc(temp_date)) THEN 
         is_holiday := true; 
        END IF; 
       END LOOP; 
      END LOOP; 

      -- add 10 hours to the duration 
      IF (NOT is_holiday) THEN 
       duration := duration + 10 * 3600; 
      END IF; 
     END IF; 
    END IF; 

    temp_date := temp_date + 1; 
END LOOP; 
RETURN duration; 
END; 

기능 무시를 주말 및 공휴일이므로 실제보다 조금 더 포괄적으로 보입니다. 도와 줘서 고마워!

감사합니다, 당신은 단순히 두 날짜를 뺄 수 오라클에서 알렉스

답변

0

. 넌 차이를 포맷 (24 * 60 * 60)

select (last_date - first_date)/(24*60*60) as seconds from table 

트릭하여 결과를 나눔으로써 시간 (초)을 계산할 수있는 것은이있다 :

이 침입이 쉬운 수있다
select to_char(trunc(sysdate) + (last_date - first_date), 'hh24:mi:ss') as time_between from table 
+0

답장을 보내 주셔서 감사합니다. 이미 날짜 사이의 차이점을 확인하기 위해이 작업을 수행하고 있습니다. 그러나 문제는 계산과 관련이 없기 때문에 오후 6시와 8시 사이의 간격을 빼는 것입니다. – alexhanschke

2

  1. 제 1 부분 일 (있는 경우)
  2. 마지막 날 부분 (만약 있다면)
  3. ,745,151 : 3 부에
  4. 개재 전체 (첫 번째 날에 LAST_DATE 오후 6시)의 이전 일 (있는 경우)
  5. 첫 번째 부분 날의 이후부터이다

가 (오전 8시, 시작 시간), 그래서 우리는에 사람들을 빼기 첫날의 시간을 얻을 :

greatest (least (trunc(first_date)+18/24 
         , last_date 
         ) - greatest(first_date 
            , trunc(first_date)+8/24 
            ) 
       , 0) * 24 as last_day_hours 

외부 greatest 기능은 우리가 음의 값의 예를하지 않도록합니다 시작 시간이 오후 6시 이후라면.

최종일 후 마지막 부분 일의 마지막 날 (종료 시간) 오전 8 내지 첫날과 동일하지 않은 경우 :

case when trunc(last_date) != trunc(first_date) 
     then greatest (least(last_date 
          , trunc(last_date)+18/24 
          ) 
         - (trunc(last_date)+8/24) 
         , 0) * 24 
     else 0 end as last_day_hours 

개재 전체 일 (시간)이다 :

greatest ((trunc(last_date) - (trunc(first_date)+1)) 
      , 0 
      ) * 10 as intervening_days_in_hours 

10 오전 8시 사이의 시간 수 오후 6 인

그래서 함께 이들 3 개 값을 가산 기간의 전체 시간을 제공하고 (3600)로 전체를 곱하여 세코을 준다 nds :

(
    (greatest (least (trunc(first_date)+18/24 
        , last_date 
        ) - greatest(first_date 
           , trunc(first_date)+8/24 
           ) 
      , 0) * 24) 
+ case when trunc(last_date) != trunc(first_date) 
     then greatest (least(last_date 
          , trunc(last_date)+18/24 
          ) 
         - (trunc(last_date)+8/24) 
         , 0) * 24 
     else 0 end 
+ (greatest ((trunc(last_date) - (trunc(first_date)+1)) 
      , 0 
      ) * 10) 
) * 3600 as total_seconds 

나는 이것보다 쉬워야한다고 생각합니다. 물론 주말은 고려하지 않습니다.