我正在尝试在过去一年中为每个月的第三个星期五创建一个表格。我知道如何一次这样做一个月但是在返回一系列日期时却遇到了麻烦。我试图使用for循环来做到这一点:
create table fridays as
begin
for i in 1..365
loop
select next_day(trunc(sysdate - i,'MM')+13,'FRIDAY') third_friday
from dual
end loop;
我是否需要有一个数组来放置这些值,或者我在其他地方出错?
答案 0 :(得分:3)
select dt
from (select dt,
row_number() over(partition by to_char(dt, 'mm') order by dt) wn
from (select trunc(sysdate, 'mm') - level dt
from dual
connect by level < 365)
where to_char(dt, 'd') = 6)
where wn = 3
更新参考@APC的评论:
如果您不想依赖NLS_TERRITORY,那么您可以这样做:
select dt
from (select dt,
row_number() over(partition by to_char(dt, 'mm') order by dt) wn
from (select trunc(sysdate, 'mm') - level dt
from dual
connect by level < 365)
where to_char(dt, 'dy', 'nls_date_language=AMERICAN') = 'fri')
where wn = 3
答案 1 :(得分:1)
这是一种略显笨重但最直观的方法:
select next_day(
next_day(
next_day(
add_months(date '2000-01-01',rownum-1)-1,
'THURSDAY'),
'THURSDAY'),
'THURSDAY')
from dual
connect by level <= 12
答案 2 :(得分:0)
这些棘手的相对日期问题的一个方便的技巧是使用DBMS_Schedular日历语法,我写了{I} here和here。
DBMS_Scheduler具有非常全面的日历语法,非常适合复杂的日历规范(一旦习惯),而Evaluate_Calendar_String函数会在提供的日期之后返回符合日程规范的下一个时间戳。
这是代码:
create or replace type timestamp_table_type
is
table of timestamp;
/
create or replace function
list_of_dates (
calendar_string varchar2,
start_date TIMESTAMP WITH TIME ZONE,
stop_date TIMESTAMP WITH TIME ZONE)
return
timestamp_table_type
pipelined
is
l_return_date_after TIMESTAMP WITH TIME ZONE := start_date - interval '1' second;
l_next_run_date TIMESTAMP WITH TIME ZONE;
begin
loop
DBMS_SCHEDULER.EVALUATE_CALENDAR_STRING(
calendar_string => list_of_dates.calendar_string,
start_date => list_of_dates.start_date,
return_date_after => l_return_date_after,
next_run_date => l_next_run_date);
exit when list_of_dates.l_next_run_date > coalesce(list_of_dates.stop_date,date '9999-12-31');
pipe row (list_of_dates.l_next_run_date);
list_of_dates.l_return_date_after := list_of_dates.l_next_run_date;
end loop;
end;
/
我认为每个月的第三个星期五会是:
begin
dbms_scheduler.create_schedule(
schedule_name => 'THIRD_THU_OF_EVERY_MONTH',
repeat_interval => 'FREQ=MONTHLY;BYDAY=5;BYSETPOS=3');
end;
/
select *
from table(
list_of_dates(
'THIRD_THU_OF_EVERY_MONTH',
sysdate ,
null));
遗憾的是,我恐怕没有Oracle系统可以用来测试它。
答案 3 :(得分:0)
这是另一个:
Select Months, Last_Fri, Total_Fridays
, (CASE WHEN Total_Fridays = 4 THEN Last_Fri-7 ELSE Last_Fri-14 END) third_fri
From
(
Select To_Char(dt,'Month') Months
, Next_Day(Last_Day(dt),'FRI')-7 Last_Fri
, Ceil(to_number(to_char(next_day(last_day(dt)-7,'FRI'),'DD'))/7) Total_Fridays
From
(
Select add_months(trunc(sysdate,'YEAR'),level-1) dt
From dual
Connect By Level <= 12
))
/
SQL>
MONTHS LAST_FRI TOTAL_FRIDAYS THIRD_FRI
--------------------------------------------------
January 1/25/2013 4 1/18/2013
February 2/22/2013 4 2/15/2013
March 3/29/2013 5 3/15/2013
April 4/26/2013 4 4/19/2013
May 5/31/2013 5 5/17/2013
June 6/28/2013 4 6/21/2013
July 7/26/2013 4 7/19/2013
August 8/30/2013 5 8/16/2013
September 9/27/2013 4 9/20/2013
October 10/25/2013 4 10/18/2013
November 11/29/2013 5 11/15/2013
December 12/27/2013 4 12/20/2013