Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
需要在oracle中查找下一个和上一个工作日_Oracle_Weekday - Fatal编程技术网

需要在oracle中查找下一个和上一个工作日

需要在oracle中查找下一个和上一个工作日,oracle,weekday,Oracle,Weekday,我的问题有点像这样: select 1 from dual where :p1_task_date in (sysdate,sysdate+1,sysdate-1) and :p1_task_id is not null 这很好,但我希望获得下一个/上一个工作日下一个/上一个星期,而不是sysdate+1和sysdate-1。我试过这样的方法: select next_day(sysdate, to_char(sysdate+1,'DAY')) from dual` 但不能继续这样做: 请帮

我的问题有点像这样:

select 1 from dual where :p1_task_date in (sysdate,sysdate+1,sysdate-1) and :p1_task_id is not null
这很好,但我希望获得下一个/上一个工作日下一个/上一个星期,而不是sysdate+1和sysdate-1。我试过这样的方法:

select next_day(sysdate, to_char(sysdate+1,'DAY')) from dual`
但不能继续这样做:


请帮忙

在不考虑节假日的情况下,您可以使用解码功能使用一周中的某一天执行一些简单的日期计算:

SELECT SYSDATE-DECODE(TO_CHAR(SYSDATE, 'D'), 2, 3, 1, 2, 1) AS WORK_DATE_BEFORE,
        TO_CHAR(SYSDATE-DECODE(TO_CHAR(SYSDATE, 'D'), 2, 3, 1, 2, 1), 'DAY') AS WORK_DAY_BEFORE,
        SYSDATE AS BASE_DATE,
        TO_CHAR(SYSDATE, 'DAY') AS BASE_DAY,
        SYSDATE+DECODE(TO_CHAR(SYSDATE, 'D'), 6, 3, 7, 2, 1) AS WORK_DATE_AFTER,
        TO_CHAR(SYSDATE+DECODE(TO_CHAR(SYSDATE, 'D'), 6, 3, 7, 2, 1), 'DAY') AS WORK_DAY_AFTER
FROM DUAL

只需将SYSDATE替换为包含要检查的日期的变量。解码是使用一周中的某一天来确定从基准日期加上或减去多少天。

我认为最好的方法是使用dbms\u scheduler来创建所有工作日的时间表。这样,您就可以根据需要对其进行调整,并且您的代码永远不必更改。创建计划后,使用dbms_scheduler.evaluate_calendar_string函数计算下一个日期。这将在星期一至星期五完成,但您可以轻松地增加日程安排,同时取消假期:

set serveroutput on 
DECLARE 
  lv_next_work_date DATE; 
BEGIN 
  dbms_scheduler.create_schedule(schedule_name=>'MY_WORKDAY_SCHEDULE', 
                                 repeat_interval=>'FREQ=DAILY;BYDAY=MON,TUE,WED,THU,FRI'); 
  dbms_scheduler.evaluate_calendar_string(start_date => trunc(sysdate), 
                                          calendar_string => 'MY_WORKDAY_SCHEDULE', 
                                          return_date_after => trunc(sysdate), 
                                          next_run_date => lv_next_work_date); 
  dbms_output.put_line(lv_next_work_date); 
END; 
/ 
另外,您还可以使用它在工作日自动执行作业


我刚才看到你也希望能做上一个工作日。这对日程安排不太方便,但可以通过快速循环完成。在今天之前两天开始,运行计划,并查看结果是否在今天之前。如果没有备份,另一天再做一次。重复此操作,直到找到上一个工作日。

@Tawman的答案会起作用,但出于可读性考虑,我更喜欢此方法:

select sysdate as current_date,
       case when to_char(sysdate,'D') in (1,6,7)
            then next_day(sysdate,'Monday')
            else sysdate+1 end as next_weekday,
       case when to_char(sysdate,'D') in (1,2,7)
            then next_day(sysdate-7,'Friday')
            else sysdate-1 end as prev_weekday
from dual

正如其他人所说,这只适用于排除周末,而不是节假日。

此过程允许您将工作日排除在节假日和周末之外:

create or replace procedure GetWorkDays(current_day in date default sysdate,
                                    next_date out date,
                                    prev_date out date) is
TYPE  HOLIDAY_TYPE IS VARRAY(17) OF varchar(5);
--List all holidays here
holidays HOLIDAY_TYPE := HOLIDAY_TYPE('01.01','02.01','03.01','04.01',
                                    '05.01','06.01','07.01','08.01',
                                    '23.02','08.03','01.05','02.05',
                                    '03.05','09.05','10.05','12.06',
                                    '04.11'); 
--Internal functions-------------------------------------------------
function IsHoliday(currentDay date) return number is
begin
for i in holidays.first..holidays.last
   loop
       if to_char(currentDay,'DD.MM') = holidays(i) then return 1;
       end if;
   end loop;
return 0;
end;

function GetNextWorkDay(currentDay date) return date is
tempDate Date;
begin
tempDate:=currentDay+1;
while IsHoliday(tempDate)=1 loop
   tempDate:=tempDate+1;
end loop;
if to_char(tempDate,'D') in (6,7) then
   tempDate:=next_day(tempDate,'Monday');
end if;
if IsHoliday(tempDate)=1 then return GetNextWorkDay(tempDate);
else return tempDate;
end if;
end;

function GetPrevWorkDay(currentDay date) return date is
tempDate Date;
begin
tempDate:=currentDay-1;
while IsHoliday(tempDate)=1 loop
   tempDate:=tempDate-1;
end loop;
if to_char(tempDate,'D') in (6,7) then
   tempDate:=next_day(tempDate-7,'Friday');
end if;
if IsHoliday(tempDate)=1 then return GetPrevWorkDay(tempDate);
else return tempDate;
end if;
end;
------------------------------------------------------------------
begin

next_date:=GetNextWorkDay(current_day);
prev_date:=GetPrevWorkDay(current_day);

end GetWorkDays;
select 
       in_date,  
       case when next_day(in_date,'Monday')>next_day(in_date,'Friday') 
                then in_date+1 else next_day(in_date,'Monday') end next_w_day, 
       case when next_day(in_date-8,'Friday')<next_day(in_date-8,'Monday') 
                then in_date-1 else next_day(in_date-7,'Friday') end previous_w_day
from 
       (select trunc(sysdate)+rownum in_date from 
                (select * from all_objects where rownum<15))
                order by in_date
只跳过周末:

create or replace procedure GetWorkDays(current_day in date default sysdate,
                                    next_date out date,
                                    prev_date out date) is
TYPE  HOLIDAY_TYPE IS VARRAY(17) OF varchar(5);
--List all holidays here
holidays HOLIDAY_TYPE := HOLIDAY_TYPE('01.01','02.01','03.01','04.01',
                                    '05.01','06.01','07.01','08.01',
                                    '23.02','08.03','01.05','02.05',
                                    '03.05','09.05','10.05','12.06',
                                    '04.11'); 
--Internal functions-------------------------------------------------
function IsHoliday(currentDay date) return number is
begin
for i in holidays.first..holidays.last
   loop
       if to_char(currentDay,'DD.MM') = holidays(i) then return 1;
       end if;
   end loop;
return 0;
end;

function GetNextWorkDay(currentDay date) return date is
tempDate Date;
begin
tempDate:=currentDay+1;
while IsHoliday(tempDate)=1 loop
   tempDate:=tempDate+1;
end loop;
if to_char(tempDate,'D') in (6,7) then
   tempDate:=next_day(tempDate,'Monday');
end if;
if IsHoliday(tempDate)=1 then return GetNextWorkDay(tempDate);
else return tempDate;
end if;
end;

function GetPrevWorkDay(currentDay date) return date is
tempDate Date;
begin
tempDate:=currentDay-1;
while IsHoliday(tempDate)=1 loop
   tempDate:=tempDate-1;
end loop;
if to_char(tempDate,'D') in (6,7) then
   tempDate:=next_day(tempDate-7,'Friday');
end if;
if IsHoliday(tempDate)=1 then return GetPrevWorkDay(tempDate);
else return tempDate;
end if;
end;
------------------------------------------------------------------
begin

next_date:=GetNextWorkDay(current_day);
prev_date:=GetPrevWorkDay(current_day);

end GetWorkDays;
select 
       in_date,  
       case when next_day(in_date,'Monday')>next_day(in_date,'Friday') 
                then in_date+1 else next_day(in_date,'Monday') end next_w_day, 
       case when next_day(in_date-8,'Friday')<next_day(in_date-8,'Monday') 
                then in_date-1 else next_day(in_date-7,'Friday') end previous_w_day
from 
       (select trunc(sysdate)+rownum in_date from 
                (select * from all_objects where rownum<15))
                order by in_date

若要独立于区域设置对一周中的几天进行日期计算,可以使用该区域设置

上一个工作日:

(
  case 
    when (date_value - trunc(date_value,'IW')) in (5,6,0)
      then trunc(date_value-1,'IW') + 4 
    else date_value - 1
  end
) prev_working_day
下一个工作天:

(
  case 
    when (date_value - trunc(date_value,'IW')) in (4,5,6)
      then trunc(date_value+3,'IW')
    else date_value + 1
  end
) next_working_day
下面是完整的示例代码


你想只跳过星期五还是也需要跳过假日?你知道世界上有些地方周末是星期六和星期天,但其他地方使用星期五吗?你想只跳过星期五还是也需要跳过假日?好问题,如果我可以跳过假日会更好,可能我需要使用所有_对象,并拒绝假日表中规定的假日。至于问题,你是否知道在世界上的某些地方周末是周六和周日,而其他地方则是周五?我确信应用程序和db时区是相同的,所以我想不会有任何问题。注意所有涉及到\u chardate的解决方案,'D',因为它取决于您的NLS\u地域。对于某些情况,第一天是星期一,对于其他情况,星期天是星期天。如果我对\u charsysdate没有错,“D”取决于您的区域设置对于某些人来说,第一天是星期一对于其他人星期天如果我没有错,那么“D”取决于您的区域设置对于某些人来说,第一天是星期一对于其他人星期天我确认此解决方案给了我不同客户端机器上不同行为的问题:我确认对于\u charsysdate,“D”取决于NLS\U区域。因此,使用ISO Week会更好