Oracle PLSQL重复模式RFC 2445

问题描述 投票:1回答:3

我具有使用PLSQL将RFC 2445重复模式转换为Dates的必要条件。

示例:

RRULE = FREQ=DAILY;INTERVAL=5;COUNT=10

根据该规则,我需要编写一个表,其中包含该模式的下10次出现。如下图所示,将开始日期视为1/1/2019 12:00:00 AM

enter image description here

Oracle是否提供允许我执行此操作的任何PLSQL软件包?如果不是这样,是否有人知道任何PLSQL项目计划?

Ps:这与Oracle在作业计划中使用的模式完全相同。

oracle plsql recurrence rfc2445
3个回答
1
投票
可能能够做到这一点。

该包支持的语法似乎类似于RFC 2445,但不完全相同。下面的PL / SQL块根据日历字符串打印出日期。有一些复杂性,例如解析DBMS_SCHEDULER.EVALUATE_CALENDAR_STRING以确定重复计算多少次。

COUNT=10

输出:

declare
    --Test different calendar strings and start dates.
    --p_calendar_string varchar2(4000) := 'FREQ=DAILY;INTERVAL=5;';
    p_calendar_string varchar2(4000) := 'FREQ=DAILY;INTERVAL=5;COUNT=10';
    p_start_date date := timestamp '2019-01-01 00:00:00';

    v_next_run_date date;
    v_count number;
    --Find the COUNT and remove it rom the calendar string, if it exists.
    procedure get_and_remove_count(p_calendar_string in out varchar2, p_count out number) is
    begin
        if lower(p_calendar_string) like '%count%' then
            p_count := to_number(regexp_substr(p_calendar_string, 'COUNT=([0-9]+)', 1, 1, null, 1));
            p_calendar_string := regexp_replace(p_calendar_string, 'COUNT=[0-9]+;?');
        else
            p_count := 1;
        end if;
    end;
begin
    get_and_remove_count(p_calendar_string, v_count);

    --TEST
    --dbms_output.put_line('String: '||p_calendar_string||', count: '||v_count);

    --Start with the original date.
    v_next_run_date := p_start_date-1/24/60/60;

    --Loop through the COUNT and display all dates.
    for i in 1 .. v_count loop

        dbms_scheduler.evaluate_calendar_string
        (
            calendar_string   => p_calendar_string,
            start_date        => p_start_date,
            return_date_after => v_next_run_date,
            next_run_date     => v_next_run_date
        );

        dbms_output.put_line(to_char(v_next_run_date, 'mm/dd/yyyy hh:mi:ss am'));
    end loop;
end;
/

0
投票
regexp

干杯!


0
投票

Oracle设置:

Select date '2019-01-01' + (level-1) * 5 as dates From dual Connect by level <= 10;

查询

CREATE FUNCTION parseRRule( rrule IN VARCHAR2, start_date IN DATE ) RETURN SYS.ODCIDATELIST PIPELINED IS freq VARCHAR2(10) := UPPER( REGEXP_SUBSTR( rrule, '(^|;)FREQ=(MONTHLY|WEEKLY|DAILY|HOURLY)(;|$)', 1, 1, 'i', 2 ) ); inter NUMBER(4,0) := TO_NUMBER( REGEXP_SUBSTR( rrule, '(^|;)INTERVAL=(\d+)(;|$)', 1, 1, 'i', 2 ) ); cnt NUMBER(4,0) := TO_NUMBER( REGEXP_SUBSTR( rrule, '(^|;)COUNT=(\d+)(;|$)', 1, 1, 'i', 2 ) ); dt DATE := start_date; step_ds INTERVAL DAY TO SECOND; step_m NUMBER(3,0); BEGIN IF freq IS NULL OR inter IS NULL OR cnt IS NULL OR dt IS NULL THEN RETURN; END IF; IF freq = 'MONTHLY' THEN step_ds := INTERVAL '0' DAY; step_m := inter; ELSIF freq = 'WEEKLY' THEN step_ds := inter * INTERVAL '7' DAY; step_m := 0; ELSIF freq = 'DAILY' THEN step_ds := inter * INTERVAL '1' DAY; step_m := 0; ELSIF freq = 'HOURLY' THEN step_ds := inter * INTERVAL '1' HOUR; step_m := 0; ELSE NULL; -- raise exception END IF; PIPE ROW ( dt ); FOR i IN 1 .. cnt - 1 LOOP dt := ADD_MONTHS( dt + step_ds, step_m ); PIPE ROW ( dt ); END LOOP; END; /

输出

| COLUMN_VALUE || :----------- || 2019-01-01 || 2019-01-06 || 2019-01-11 || 2019-01-16 || 2019-01-21 || 2019-01-26 || 2019-01-31 || 2019-02-05 || 2019-02-10 || 2019-02-15 |

db <>小提琴SELECT *
FROM   TABLE(
  parseRRule(
    rrule      => 'FREQ=DAILY;INTERVAL=5;COUNT=10',
    start_date => DATE '2019-01-01'
  )
)

© www.soinside.com 2019 - 2024. All rights reserved.