Từ Oracle Database 11g, Oracle đã giới thiệu một hàm trong package DBMS_SCHEDULER để tính toán các lần chạy tiếp theo từ một chuỗi lịch theo cấu trúc dễ hiểu, đó chính là:
DBMS_SCHEDULER.EVALUATE_CALENDAR_STRING
Chúng ta thử bắt đầu với ví dụ đơn giản sau:
declare
v_cal_string varchar2(4000);
v_next_date timestamp;
begin
dbms_output.put_line('Now is : '||to_char(sysdate, 'DY DD-MON-YYYY HH24:MI'));
-- Calendar string for every day at 06:15
v_cal_string := 'FREQ=DAILY; BYHOUR=6; BYMINUTE=15';
dbms_scheduler.evaluate_calendar_string(
calendar_string => v_cal_string,
start_date => null,
return_date_after => null,
next_run_date => v_next_date);
dbms_output.put_line('Next Run Date is : '||to_char(v_next_date, 'DY DD-MON-YYYY HH24:MI'));
end;
/
Chạy nó và chúng ta có thể thấy được kết quả biến next_run_date chính là sáng ngày hôm sau:

Lưu ý rằng tất cả các tham số của EVALUATE_CALENDAR_STRING là bắt buộc.
Một ví dụ thú vị hơn, giả sử chúng ta cần tính ngày trả lương là ngày thứ 5 thứ 3 hàng tháng:
declare
v_cal_string varchar2(4000);
v_next_date timestamp;
begin
dbms_output.put_line('Now is : '||to_char(sysdate, 'DY DD-MON-YYYY HH24:MI'));
v_cal_string := 'FREQ=MONTHLY; BYDAY=3 THU; BYHOUR=0; BYMINUTE=0';
dbms_scheduler.evaluate_calendar_string(
calendar_string => v_cal_string,
start_date => null,
return_date_after => null,
next_run_date => v_next_date);
dbms_output.put_line('Next Payday is : '||to_char(v_next_date, 'DY DD-MON-YYYY HH24:MI'));
end;
/

Nếu bạn muốn trả về kết quả ngày sau một ngày cụ thể thì hãy sử dụng tham số: RETURN_DATE_AFTER
declare
v_weekday_string varchar2(4000) := 'FREQ=DAILY; BYDAY=MON,TUE,WED,THU,FRI; BYHOUR=6; BYMINUTE=15';
v_next_run timestamp;
v_start_from timestamp;
begin
dbms_output.put_line('Weekday...');
-- I want to know that the calendar string will hit Monday - Friday but not Saturday or Sunday
v_start_from := to_timestamp(next_day(sysdate, 'TUESDAY'));
for i in 1..5 loop
dbms_scheduler.evaluate_calendar_string(
calendar_string => v_weekday_string,
start_date => null,
return_date_after => v_start_from,
next_run_date => v_next_run);
dbms_output.put_line(to_char( v_next_run, 'Day DDth Month YYYY HH24:MI'));
-- set RETURN_DATE_AFTER to be the date last found by the string
v_start_from := v_next_run;
end loop;
end;
/

Ngoài ra chúng ta còn có thể sử dụng tham số start_date
declare
v_weekend_string varchar2(4000) := 'FREQ=DAILY; BYDAY=SAT,SUN; BYHOUR=9; BYMINUTE=30';
-- I like a lie-in at weekends
v_start_date timestamp;
v_next_run timestamp;
begin
dbms_output.put_line('Weekday...');
v_start_date := to_timestamp(next_day(systimestamp, 'MONDAY'));
for i in 1..2 loop
dbms_scheduler.evaluate_calendar_string(
calendar_string => v_weekend_string,
start_date => v_start_date,
return_date_after => null,
next_run_date => v_next_run);
dbms_output.put_line(to_char( v_next_run, 'Day DDth Month YYYY HH24:MI'));
-- Unlike the RETURN_DATE_AFTER parameter, we need to increment the start date by a day
-- in each loop iteration
v_start_date := v_next_run + 1;
end loop;
end;
/

Nếu có cách sử dụng thú vị hơn, mời bạn chia sẻ với mọi người trong phần bình luận nhé.
Leave a Review