2016-07-21 5 views
0

Startdate、Enddate、およびWorkday(nth)を渡すと、週末と休日を除いたn番目の稼働日を計算するSQL関数が既に用意されています...Oracleのn番目の稼働日を取得する

ワーキングSQL関数:私は(oracleに新)ORACLEでこの機能を再作成しようとしています

FUNCTION [dbo].[getNthWorkingDate] 
    (
@StartDate as datetime, 
@EndDate as datetime, 
@WorkDay as int 
) 
    RETURNS datetime 
    AS 
    BEGIN 
-- Declare the return variable here 
DECLARE @WorkDate as datetime, @LeaveYear as smallint,@iCount as int 
set @LeaveYear = datepart(year, @StartDate) 
set @iCount = 1 
WHILE (@StartDate < @EndDate) 
    BEGIN 

     IF (DATENAME(WEEKDAY,@StartDate) = 'SUNDAY') OR (DATENAME(WEEKDAY,@StartDate) = 'SATURDAY') 
      -- Just to keep the if statement with out code 
      set @iCount = @iCount; 
     ELSE IF EXISTS (SELECT * FROM HOLIDAYS WHERE CAST (HOLIDAY + ' ' + CAST(@LeaveYear AS VARCHAR) AS DATETIME) = @StartDate) 
      -- Just to keep the if statement with out code 
      set @iCount = @iCount; 
     ELSE 
      begin 
       set @WorkDate = @StartDate 
       if @iCount = @WorkDay 
        BREAK; 
       else 
        set @iCount = @iCount + 1; 
      end 

     set @StartDate = dateadd(day, 1, @StartDate); 
    END 
-- Return the result of the function 
RETURN @WorkDate 
END 

が、私はいくつかの変更を行いましたが、それは働いて得ることができなかった、私は中に何かが足りないと思いますルーピング、任意のヘルプは高く評価されるだろう...事前にお礼..

オラクル機能:

create or replace FUNCTION GETNTHWORKINGDATE (pStartDate DATE, 
              pEndDate DATE, 
              pWorkDay NUMBER) 
    RETURN DATE 
    AS 
    vStartDate DATE; 
    vWorkDate DATE ; 
    vCount NUMBER; 
    vHoliday DATE; 
    BEGIN 
    vCount := 1; 
    BEGIN 
    SELECT HOLIDAY_DATE INTO vHoliday FROM HOLIDAY WHERE (to_char(HOLIDAY_DATE, 'MM DD') = to_char(pStartDate, 'MM DD')); 
    EXCEPTION 
    WHEN NO_DATA_FOUND THEN  
    vHoliday := NULL; 
END;  
vStartDate := pStartDate; 

BEGIN 
WHILE (vStartDate < pEndDate) 
LOOP 
    IF (to_char(vStartDate, 'DAY') = 'SUNDAY') OR (to_char(vStartDate, 'DAY') = 'SATURDAY') THEN 
     vCount := vCount; 
    ELSIF (to_char(vHoliday, 'MM DD') = to_char(vStartDate, 'MM DD')) THEN 
     vCount := vCount; 
    ELSE  
     vWorkDate := vStartDate; 
     IF vCount = pWorkDay THEN 
     EXIT; 
     ELSE 
     vCount := vCount + 1;    
    END IF; 
    END IF; 
     vStartDate := vStartDate + 1; 
END LOOP; 

END; 

RETURN vWorkDate; 

END GETNTHWORKINGDATE; 
+0

かなり曖昧である "作業それを得ることができませんでした"。間違いはありますか?何のエラー?あなたは間違った結果を得ますか?あなたはどのようなパラメーターを渡していますか、どのような結果が欲しいのですか?どのような結果が得られますか? –

+0

私は間違った結果を得ています。シナリオ1:私はstartdate:07/20/2016、end date:07/30/2016、そしてworking dayを1とします。第1作業日07/20/2016、この結果が得られました。それは正しいです。シナリオ2:同じ入力については、休日として07/20/2016を設定します。作業日として07/21/2016を取得しています。そうです。週末は除外されていません。出発日に07/16を渡すと、土曜日の結果として07/16が与えられます。最初の作業日は07/18になるはずです。 – user6621250

+0

また、開始日が休日でない休日を計算していない場合、scenario3:07/20は休日です。私は07/19を開始日と2日として渡すので、結果として07/21を取得する必要があります。それは休日のテーブルの休日として設定されて私に07/20を与えています。 – user6621250

答えて

0
 create or replace FUNCTION GETNTHWORKINGDATE (pStartDate DATE, 
              pEndDate DATE, 
              pWorkDay NUMBER) 
RETURN DATE AS 
vStartDate DATE; 
vWorkDate DATE ; 
vCount NUMBER; 
vHoliday DATE; 

BEGIN 
vCount := 1; 
vStartDate := pStartDate; 
BEGIN 
WHILE (vStartDate < pEndDate) 
    LOOP 
     BEGIN 
      --Select Holiday Month and Date into vHoliday Variable when Start Date is a holiday. 
      SELECT HOLIDAY_DATE INTO vHoliday FROM HOLIDAY WHERE (to_char(HOLIDAY_DATE, 'MM DD') = to_char(vStartDate, 'MM DD')); 
      EXCEPTION 
      WHEN NO_DATA_FOUND THEN vHoliday := NULL; 
     END; 

    -- Code to eliminate Weekends 
    IF (to_char(vStartDate, 'D') = 1) OR (to_char(vStartDate, 'D') = 7) THEN 
     vCount := vCount; 

    --Code to eliminate Holiday's from holiday table. 
    ELSIF (to_char(vHoliday, 'MM DD') = to_char(vStartDate, 'MM DD')) THEN 
     vCount := vCount; 
    ELSE  
     vWorkDate := vStartDate; 
     IF vCount = pWorkDay THEN 
     EXIT; 
     ELSE 
     vCount := vCount + 1;    
     END IF; 
    END IF; 
    vStartDate := vStartDate + 1; 
    END LOOP;  
    END; 

RETURN vWorkDate; 

END GETNTHWORKINGDATE; 
1

このような機能は、プレーンSQLで機能します。 PL/SQLを使用する必要がない場合は、PL/SQLを使用しない方がよいでしょう。それを使用する必要がある場合は、必要に応じて適応してください。私はあなたが既に要件を変更したコメントを参照してください。必要に応じて適応してください。

「マジックナンバー」2 * :wd_number + 5は、少なくとも:wd_number平日の就業日を含む十分な暦日を追加するためのものです。 +5:wd_numberの低い値です。これは最も効率的な解決策ではありませんが、数ミリ秒以上の時間を無駄にすることはありませんので、効率を上げるのは面倒ではありません。

with holidays(holiday_date, holiday_name) as (
     select date '2016-01-01', 'New Year''s Day' from dual union all 
     select date '2016-04-01', 'April Fools'' Day' from dual union all 
     select date '2016-05-01', 'May First'   from dual 
    ), 
    work_days (dt) as (
     select to_date(:start_date, 'yyyy-mm-dd') + level - 1 
     from dual 
     where to_char(to_date(:start_date, 'yyyy-mm-dd') + level - 1, 'Dy') 
                    not in ('Sat', 'Sun') 
     connect by level < 2 * to_number(:wd_number) + 5 
     minus 
     select holiday_date 
     from holidays 
    ), 
    ordered_work_days (dt, rn) as (
     select dt, row_number() over (order by dt) 
     from work_days 
    ) 
select dt 
from ordered_work_days 
where rn = to_number(:wd_number) 
; 
+0

ありがとうmathguy、私は私自身の機能で何をしていたのかもっと興味があったので、最終的に私は 'DAY' = 'SATURDAY'の時に、to_charの出力に 'vStartDate '、' DAY)は 'SATURDAY'で、 'SUNDAY'は3つのスペースがあったので、それを無視していたのです。私はそれを以下のコードに置き換えて動作させています。 – user6621250

+0

@ user6621250 - 右'DAY'形式を使用すると、FIXED LENGTH文字形式の値、つまり使用する言語で最も長い曜日の長さが返されます。 WEDNESDAYは9桁の文字なので、他の曜日には9桁の文字を埋めるためのスペースが埋められます。あなたが私に尋ねるなら、それはまったくばかげた行動ですが、私はオラクルではありません。多分彼らには何らかの理由があったでしょう。これは私がしたように 'DY'を使う方が良い理由です - 'DY'と 'SAT'または 'SUN'を比較してください。 (大文字も小文字も注記:私は 'Dy'と 'Sat'と 'Sun'を使いました)。それ以外は、プレーンSQLはほとんど常にPL/SQLより優れています – mathguy

+0

これはすべてを説明しています..ありがとうございます。 – user6621250

関連する問題