在Oracle

时间:2016-07-21 17:31:31

标签: oracle plsql oracle11g

我们已经在SQL中有一个函数计算第n个工作日期,不包括周末和假日,当你通过Startdate,Enddate和Workday(nth)时......它给你第n个工作日...

使用SQL函数:

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

我正在尝试在ORACLE(oracle的新手)中重新创建此功能,我做了一些更改,但无法使其正常工作,我想我在循环中缺少一些东西,任何帮助都会受到赞赏。 ..提前致谢..

ORACLE功能:

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;

3 个答案:

答案 0 :(得分:1)

像这样的东西 - 在纯SQL中。如果你真的不需要使用PL / SQL,最好不要使用它。如果您确实需要使用它,请根据需要进行调整。我在评论中看到你已经改变了要求;根据需要进行调整。

&#34;幻数&#34; 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)
;

答案 1 :(得分: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;

答案 2 :(得分:0)

------排除周末并计算第N个工作日 选择--CURRENTDATE WORK_DATE, WORK_DAY, ROW_NUMBER()已于NTH_WORKING_DAY(在WORK_DATE之前订购) 从 ( ---按日期获取所有日期 选择货币, FIRST_DATE +(等级-1)作为WORK_DATE, TO_CHAR(FIRST_DATE +(LEVEL-1),'DAY')AS WORK_DAY 从 ( -获取每月的当前日期,第一个日期和最后一个日期 SELECT sysdate CURRENTDATE, TRUNC(sysdate,'MM')AS FIRST_DATE, LAST_DAY(sysdate)LAST_DATE 从双重 ) CONNECT BY FIRST_DATE +(level-1)<= LAST_DATE ) TRIM(WORK_DAY)不在('SATURDAY','SUNDAY');