创建特定历史日期的表oracle sql

时间:2013-01-30 11:16:36

标签: sql oracle oracle10g date-arithmetic

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

答案 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

Here is a sqlfiddle demo


更新参考@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} herehere

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