2

我正在尝试为过去一年中的每个月创建一个包含该月第三个星期五的表格。我知道如何一次做一个月,但在返回一系列日期时遇到了麻烦。我尝试使用 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;

我是否需要有一个数组来将这些值放入或者我在其他地方出错了?

4

4 回答 4

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

这是一个 sqlfiddle 演示


更新参考@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
于 2013-01-30T11:40:31.357 回答
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
于 2013-01-30T12:18:24.817 回答
0

对于这些棘手的相对日期问题,一种方便的技术是使用 DBMS_Schedular 日历语法,我在此处此处写过。

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 系统来测试它。

于 2013-01-30T12:05:21.517 回答
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
于 2013-01-30T16:17:53.557 回答