【问题标题】:Creating table of specific historic dates oracle sql创建特定历史日期表oracle sql
【发布时间】:2013-01-14 04:35:27
【问题描述】:

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

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

【问题讨论】:

  • 要使create table ... as 语句起作用,您必须使用纯 SQL(如下面的 A.B.Cade 的解决方案)。放置 begin ... end; 块是 PL/SQL,它不起作用。

标签: sql oracle oracle10g date-arithmetic


【解决方案1】:

你的意思是这样的吗?

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

【讨论】:

  • 此解决方案部署数据掩码“D”;星期几因 NLS_TERRITORY 而异,因此对于其他 NLS 设置,6 可能是星期四或星期六。
  • @A.B.Cade 谢谢,这几乎就是我想要的。我希望它从 sysdate -1 开始查找,以便第一个条目应该是 2013 年 1 月 18 日。此解决方案是否也仅限于一年范围,或者您可以将其延长到 5 年吗?
  • 年份由level &lt; 365生成。这是(非闰年)中的天数。通过所需的度数生成更多年的 365 记录。
  • 感谢@APC 的评论
  • @alloemf,如果您想包含当前月份,请将 trunc(sysdate, 'mm') 更改为 trunc(last_day(sysdate)) 在此处查看演示 sqlfiddle.com/#!4/d41d8/6722
【解决方案2】:

这是一个有点笨拙但最直观的方法:

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

【讨论】:

  • 如果一个月的第一天本身就是星期四,我认为这个解决方案将在第四个星期四交付。
  • 我认为没关系 - 我从 add_months() 结果中减去一天,以便在上个月的最后一天之后找到第三次出现。
【解决方案3】:

解决这些棘手的相对日期问题的一种方便技术是使用 DBMS_Schedular 日历语法,我写过关于 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 系统来测试它。

【讨论】:

    【解决方案4】:

    这是另一个:

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-01-13
      • 2018-03-25
      • 2023-03-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多