понедельник, 20 мая 2019 г.

Расписание запусков

Есть матрица расписания запусков:








Первая строка – 15-и минутные интервалы, вторая строка часовые интервалы, третья строка
дни недели, четвертая дни месяца, пятая месяцы года. С помощью данной матрицы задается периодичность запусков.

Требуется написать функцию на Oracle PL/SQL, которая бы возвращала дату следующего запуска (тип Date) от двух входных параметров:
Первый параметр (тип Date): дата, от которой ведется отчет;
Второй параметр (тип Varchar2): это текстовая переменная, в которой перечислены все выбранные ячейки. Ячейки разделены «,» (запятой), а строки разделены «;» (точкой с запятой), например, для данного рисунка расписание будет выглядеть следующим образом: 0,45;0,4,8,12,17,22;2,6;1,2,3,4,5,11,18,24;1,2,3,9,11;

Контрольный пример:
Дата отсчета: 09.07.2010 23:36
Строка: 0,45;12;1,2,6;3,6,14,18,21,24,28;1,2,3,4,5,6,7,8,9,10,11,12;
Результат: 18.07.2010 12:00

Примечание. В данном примере, используется американский календарь, в котором 1 – это воскресенье, 2 – понедельник и т.д.

Решение: 

DECLARE
    p_interval   VARCHAR2(250);
    d1           TIMESTAMP := SYSDATE;
    d2           TIMESTAMP := d1;
    p_result_day TIMESTAMP;
    v_byminute  VARCHAR2(50);
    v_byhour    VARCHAR2(50);
    v_byweekday VARCHAR2(50);
    v_bymontday VARCHAR2(50);
    v_bymonth   VARCHAR2(50);
    v_slr_name  VARCHAR2(30) := 'slr' || to_char(systimestamp'yyymmddhh24missff');
BEGIN
    p_interval  := '0,15,45;0,4,8,12,17,22;2,4,5,6;1,2,3,4,5,11,18,24;1,2,3,9,11;'-- в конце можно не ставить ;
    v_byminute  := regexp_substr(p_interval'[^;]+'11);
    v_byhour    := regexp_substr(p_interval'[^;]+'12);
    v_byweekday := regexp_substr(p_interval'[^;]+'13);
    v_bymontday := regexp_substr(p_interval'[^;]+'14);
    v_bymonth   := regexp_substr(p_interval'[^;]+'15);
    -- преобразуем дни в наименования
    SELECT listagg(regexp_substr('SUN|MON|TUE|WED|THU|FRI|SAT''[^|]+'1dy),','within GROUP(ORDER BY dy)
    INTO   v_byweekday
    FROM   (SELECT regexp_substr(v_byweekday'[^,]+'1LEVELdy
            FROM   dual
            CONNECT BY LEVEL <= regexp_count(v_byweekday',') + 1);
    -- создаем уникальный календарь
    dbms_scheduler.create_schedule(schedule_name => v_slr_name,
    repeat_interval => 'FREQ=YEARLY;BYMONTHDAY='||v_bymontday||';BYDAY=' || v_byweekday||';BYHOUR='||v_byhour||';BYMINUTE='||v_byminute);
    dbms_scheduler.evaluate_calendar_string(calendar_string   => v_slr_name,
                                            start_date        => d1,
                                            return_date_after => d2,
                                            next_run_date     => p_result_day);
    dbms_output.put_line('Next date is ' || to_char(p_result_day'dd.mm.yyyy hh24:mi:ss'));
    -- удаляем созданный календарь
    dbms_scheduler.drop_schedule(schedule_name => v_slr_name);
END;
/

Комментариев нет:

Отправить комментарий