1

我正在为我的 oracle DB 创建一个调度程序这是我到目前为止得到的:

BEGIN 
DBMS_SCHEDULER.CREATE_JOB (
job_name            => 'CREAZIONE_OCCORRENZE',
job_type            => 'STORED_PROCEDURE',
job_action          => 'pop_occr_lezione'
start_date          =>  A,
end_date            =>  B,
repeat_interval     => 'FREQ=WEEKLY'
enabled             => true,
auto_drop           => false;
)
END;
BEGIN
DBMS_SCHEDULER.CREATE_JOB (
job_name            => 'ASSEGNAZIONE - AULE',
job_type            => 'STORED_PROCEDURE',
job_action          => 'ass_aule'
start_date          =>  C,
end_date            =>  D,
repeat_interval     => 'FREQ=WEEKLY'
enabled             => true,
auto_drop           => false;
)
END;
/

如您所见,我仍然需要为 2 个作业设置 start_date 和 end_date。Wich 相当令人困惑,我该如何设置:

A = 八月的最后一个星期一(每年有效)

B = 8 月的第一个星期一( A 的一年后)

C = A 之后的第一个星期日

D = B 之后的第一个星期日

我怎么能做这样的事情?

4

3 回答 3

2

start_date并且end_date固定值,即您不能说“八月的最后一个星期一(每年有效)”。start_date仅用于 的初始值repeat_interval

例如start_date => TIMESTAMP '2015-03-26 18:00:00', repeat_interval => 'FREQ=WEEKLY'表示每周一的 18:00:00。

end_date是您的工作被禁用的日期。

repeat_interval因为“八月的每个最后一个星期一”将是FREQ=MONTHLY;INTERVAL=1;BYMONTH=AUG;BYDAY=-1 MON

repeat_interval因为“八月的每个第一个星期日”将是FREQ=MONTHLY;INTERVAL=1;BYMONTH=AUG;BYDAY=1 SUN

您可以使用此过程进行验证:

DECLARE
    next_run_date TIMESTAMP WITH TIME ZONE;
BEGIN
    FOR i IN 1..10 LOOP
        DBMS_SCHEDULER.EVALUATE_CALENDAR_STRING('FREQ=MONTHLY;INTERVAL=1;BYMONTH=AUG;BYDAY=-1 MON', NULL, next_run_date, next_run_date);
        DBMS_OUTPUT.PUT_LINE ( TO_CHAR(next_run_date, 'yyyy-mm-dd fmDay') );
    END LOOP;

    next_run_date := NULL;
    FOR i IN 1..10 LOOP
        DBMS_SCHEDULER.EVALUATE_CALENDAR_STRING('FREQ=MONTHLY;INTERVAL=1;BYMONTH=AUG;BYDAY=1 SUN', NULL, next_run_date, next_run_date);
        DBMS_OUTPUT.PUT_LINE ( TO_CHAR(next_run_date, 'yyyy-mm-dd fmDay') );
    END LOOP;

END;

2015-08-31 Monday
2016-08-29 Monday
2017-08-28 Monday
2018-08-27 Monday
2019-08-26 Monday
2020-08-31 Monday
2021-08-30 Monday
2022-08-29 Monday
2023-08-28 Monday
2024-08-26 Monday

2015-08-30 Sunday
2016-08-28 Sunday
2017-08-27 Sunday
2018-08-26 Sunday
2019-08-25 Sunday
2020-08-30 Sunday
2021-08-29 Sunday
2022-08-28 Sunday
2023-08-27 Sunday
2024-08-25 Sunday

检查日历语法以获取更多详细信息

基于此,您可以创建另一个设置start_date主要工作的工作,即:

BEGIN
DBMS_SCHEDULER.CREATE_JOB (
   job_name            => 'SET_START_TIME',
   job_type            => 'PLSQL_BLOCK',
   job_action          => 'BEGIN DBMS_SCHEDULER.SET_ATTRIBUTE(''CREAZIONE_OCCORRENZE'', ''START_DATE'', LOCALTIMESTAMP); END;',
   repeat_interval     => 'FREQ=MONTHLY;INTERVAL=1;BYMONTH=AUG;BYDAY=-1 MON'
   enabled             => TRUE,
   auto_drop           => FALSE);
END;
于 2015-03-23T18:39:01.733 回答
0

You can use this query to get the info ... then you just have to stuff the values into your dbms_scheduler. If you need to do this every year, you may need to use dynamic sql to call the scheduler.

  with w_current as (
        select add_months(trunc(sysdate,'YYYY'),7+12) aug1,
               last_day(add_months(trunc(sysdate,'YYYY'),7)) aug31
          from dual
        ),
     w_mondays as (
           select  aug1+mod(9-to_char(aug1,'D'),7) first_mon_aug,
                   aug31+mod(8-to_char(aug31,'D'),7)-6  last_mon_aug
             from w_current
        )
  select first_mon_aug, last_mon_aug,
         first_mon_aug+6   first_sun_after_A,
         last_mon_aug+6    first_sun_after_B
    from w_mondays;
于 2015-03-23T18:37:03.610 回答
0

我很困惑,您正在混合周一和周日(2015-07-12 是周一,而不是周日)并且您更改了问题中的要求。

据我了解您的日程安排,为了简化,您喜欢CREAZIONE_OCCORRENZE每周一工作,除了“7 月的第二个星期一到最后一个星期一,但 8 月的一个星期一”。作业ASSEGNAZIONE_AULE总是在五天后运行。

然后你可以使用排除项。应该是这个:

BEGIN
DBMS_SCHEDULER.CREATE_SCHEDULE (
    schedule_name => 'MONDAY_AUGUST',
   repeat_interval => 'FREQ=MONTHLY;INTERVAL=1;BYMONTH=AUG;BYDAY=-5 MON,-4 MON,-3 MON,-2 MON');

DBMS_SCHEDULER.CREATE_SCHEDULE (
    schedule_name => 'MONDAY_JULY',
   repeat_interval => 'FREQ=MONTHLY;INTERVAL=1;BYMONTH=JUL;BYDAY=2 MON,3 MON,4 MON,5 MON');

DBMS_SCHEDULER.CREATE_SCHEDULE (
    schedule_name => 'MONDAYS',
   repeat_interval => 'FREQ=WEEKLY;INTERVAL=1;BYDAY=MON;EXCLUDE=MONDAY_AUGUST,MONDAY_JULY');

DBMS_SCHEDULER.CREATE_SCHEDULE (
    schedule_name => 'SUNDAYS',
   repeat_interval => 'MONDAYS+OFFSET:6D');
END;


BEGIN 
DBMS_SCHEDULER.CREATE_JOB (
   job_name            => 'CREAZIONE_OCCORRENZE',
   job_type            => 'STORED_PROCEDURE',
   job_action          => 'pop_occr_lezione'
   start_date          =>  NULL,
   end_date            =>  NULL,
   repeat_interval     => 'MONDAYS'
   enabled             => true,
   auto_drop           => false);

DBMS_SCHEDULER.CREATE_JOB (
   job_name            => 'ASSEGNAZIONE - AULE',
   job_type            => 'STORED_PROCEDURE',
   job_action          => 'ass_aule'
   start_date          =>  NULL,
   end_date            =>  NULL,
   repeat_interval     => 'SUNDAYS'
   enabled             => true,
   auto_drop           => false);
END;
/

以及用于测试计划的 PL/SQL 块:

DECLARE
    next_run_date TIMESTAMP WITH TIME ZONE;
BEGIN

    next_run_date := NULL;  
    DBMS_OUTPUT.PUT_LINE ('Excluded Mondays in August' );
    FOR i IN 1..10 LOOP
        DBMS_SCHEDULER.EVALUATE_CALENDAR_STRING('MONDAY_AUGUST', NULL, next_run_date, next_run_date);
        DBMS_OUTPUT.PUT_LINE ( TO_CHAR(next_run_date, 'yyyy-mm-dd wTH fmDay') );
    END LOOP;

    next_run_date := NULL;  
    DBMS_OUTPUT.PUT_LINE ('Excluded Mondays in July' );
    FOR i IN 1..10 LOOP
        DBMS_SCHEDULER.EVALUATE_CALENDAR_STRING('MONDAY_JULY', NULL, next_run_date, next_run_date);
        DBMS_OUTPUT.PUT_LINE ( TO_CHAR(next_run_date, 'yyyy-mm-dd wTH fmDay') );
    END LOOP;

    next_run_date := NULL;  
    DBMS_OUTPUT.PUT_LINE ('Executions Job 1' );
    FOR i IN 1..150 LOOP
        DBMS_SCHEDULER.EVALUATE_CALENDAR_STRING('MONDAYS', NULL, next_run_date, next_run_date);
        IF TO_CHAR(next_run_date, 'IW') BETWEEN 25 AND 38 THEN -- avoid excessive output
            DBMS_OUTPUT.PUT_LINE ( TO_CHAR(next_run_date, 'yyyy-mm-dd wTH fmDay') );
        END IF;
    END LOOP;

    next_run_date := NULL;
    DBMS_OUTPUT.PUT_LINE ('Executions Job 2' );
    FOR i IN 1..150 LOOP
        DBMS_SCHEDULER.EVALUATE_CALENDAR_STRING('SUNDAYS', NULL, next_run_date, next_run_date);
        IF TO_CHAR(next_run_date, 'IW') BETWEEN 25 AND 38 THEN -- avoid excessive output
            DBMS_OUTPUT.PUT_LINE ( TO_CHAR(next_run_date, 'yyyy-mm-dd wTH fmDay') );
        END IF;
    END LOOP;

END;


Excluded Mondays in August
2015-08-03 1st Monday
2015-08-10 2nd Monday
2015-08-17 3rd Monday
2015-08-24 4th Monday
2016-08-01 1st Monday
2016-08-08 2nd Monday
2016-08-15 3rd Monday
2016-08-22 4th Monday
2017-08-07 1st Monday
2017-08-14 2nd Monday

Excluded Mondays in July
2015-07-13 2nd Monday
2015-07-20 3rd Monday
2015-07-27 4th Monday
2016-07-11 2nd Monday
2016-07-18 3rd Monday
2016-07-25 4th Monday
2017-07-10 2nd Monday
2017-07-17 3rd Monday
2017-07-24 4th Monday
2017-07-31 5th Monday

Executions Job 1
2015-06-15 3rd Monday
2015-06-22 4th Monday
2015-06-29 5th Monday
2015-07-06 1st Monday
2015-08-31 5th Monday
2015-09-07 1st Monday
2015-09-14 2nd Monday
2016-06-20 3rd Monday
2016-06-27 4th Monday
2016-07-04 1st Monday
2016-08-29 5th Monday
2016-09-05 1st Monday
2016-09-12 2nd Monday
2016-09-19 3rd Monday
2017-06-19 3rd Monday
2017-06-26 4th Monday
2017-07-03 1st Monday
2017-08-28 4th Monday
2017-09-04 1st Monday
2017-09-11 2nd Monday
2017-09-18 3rd Monday
2018-06-18 3rd Monday
2018-06-25 4th Monday
2018-07-02 1st Monday

Executions Job 2
2015-06-21 3rd Sunday
2015-06-28 4th Sunday
2015-07-05 1st Sunday
2015-07-12 2nd Sunday
2015-09-06 1st Sunday
2015-09-13 2nd Sunday
2015-09-20 3rd Sunday
2016-06-26 4th Sunday
2016-07-03 1st Sunday
2016-07-10 2nd Sunday
2016-09-04 1st Sunday
2016-09-11 2nd Sunday
2016-09-18 3rd Sunday
2016-09-25 4th Sunday
2017-06-25 4th Sunday
2017-07-02 1st Sunday
2017-07-09 2nd Sunday
2017-09-03 1st Sunday
2017-09-10 2nd Sunday
2017-09-17 3rd Sunday
2017-09-24 4th Sunday
2018-06-24 4th Sunday
2018-07-01 1st Sunday
2018-07-08 2nd Sunday
于 2015-03-24T07:47:37.423 回答