使用SQL生成一系列日期

时间:2009-01-06 21:48:29

标签: sql oracle

我有一个带有日期参数的SQL查询(如果我将它扔进一个函数中),我需要在去年的每一天运行它。

如何生成过去365天的列表,以便我可以使用直接SQL来执行此操作?

显然,生成列表0..364也可以,因为我总是可以:

SELECT SYSDATE - val FROM (...);

16 个答案:

答案 0 :(得分:80)

无需使用超大表或ALL_OBJECTS表:

SELECT TRUNC (SYSDATE - ROWNUM) dt
  FROM DUAL CONNECT BY ROWNUM < 366

会做到这一点。

答案 1 :(得分:9)

 SELECT (sysdate-365 + (LEVEL -1)) AS DATES
 FROM DUAL connect by level <=( sysdate-(sysdate-365))

如果替换'from'和'to'日期代替sysdate和sysdate-365,则输出将是from和date之间的日期范围。

答案 2 :(得分:5)

最近我遇到了类似的问题并通过这个简单的查询解决了这个问题:

SELECT
  (to_date(:p_to_date,'DD-MM-YYYY') - level + 1) AS day
FROM
  dual
CONNECT BY LEVEL <= (to_date(:p_to_date,'DD-MM-YYYY') - to_date(:p_from_date,'DD-MM-YYYY') + 1);

实施例

SELECT
  (to_date('01-05-2015','DD-MM-YYYY') - level + 1) AS day
FROM
  dual
CONNECT BY LEVEL <= (to_date('01-05-2015','DD-MM-YYYY') - to_date('01-04-2015','DD-MM-YYYY') + 1);

结果

01-05-2015 00:00:00
30-04-2015 00:00:00
29-04-2015 00:00:00
28-04-2015 00:00:00
27-04-2015 00:00:00
26-04-2015 00:00:00
25-04-2015 00:00:00
24-04-2015 00:00:00
23-04-2015 00:00:00
22-04-2015 00:00:00
21-04-2015 00:00:00
20-04-2015 00:00:00
19-04-2015 00:00:00
18-04-2015 00:00:00
17-04-2015 00:00:00
16-04-2015 00:00:00
15-04-2015 00:00:00
14-04-2015 00:00:00
13-04-2015 00:00:00
12-04-2015 00:00:00
11-04-2015 00:00:00
10-04-2015 00:00:00
09-04-2015 00:00:00
08-04-2015 00:00:00
07-04-2015 00:00:00
06-04-2015 00:00:00
05-04-2015 00:00:00
04-04-2015 00:00:00
03-04-2015 00:00:00
02-04-2015 00:00:00
01-04-2015 00:00:00

答案 3 :(得分:3)

Oracle特定,并且不依赖于预先存在的大型表或复杂的系统视图而非数据字典对象。

SELECT c1 from dual
  MODEL DIMENSION BY (1 as rn)  MEASURES (sysdate as c1)
  RULES ITERATE (365) 
  (c1[ITERATION_NUMBER]=SYSDATE-ITERATION_NUMBER)
order by 1

答案 4 :(得分:3)

Oracle中经常使用的方法是这样的:

select trunc(sysdate)-rn
from
(   select rownum rn
    from   dual
    connect by level <= 365)
/

就个人而言,如果一个应用程序需要一个日期列表,那么我只是用它们创建一个表,或者创建一个包含一系列整数的表,这些表达式可达一百万,可用于此类事情。

答案 5 :(得分:3)

大约一年半为时已晚,但对于后人来说,这是Teradata的一个版本:

SELECT calendar_date 
FROM SYS_CALENDAR.Calendar
WHERE SYS_CALENDAR.Calendar.calendar_date between '2010-01-01' (date) and '2010-01-03' (date)

答案 6 :(得分:3)

日期范围介于12/31/1996和12/31/2020之间

SELECT dt, to_char(dt, 'MM/DD/YYYY') as date_name, 
  EXTRACT(year from dt) as year, 
  EXTRACT(year from fiscal_dt) as fiscal_year,
  initcap(to_char(dt, 'MON')) as month,
  to_char(dt, 'YYYY')        || ' ' || initcap(to_char(dt, 'MON')) as year_month,
  to_char(fiscal_dt, 'YYYY') || ' ' || initcap(to_char(dt, 'MON')) as fiscal_year_month,
  EXTRACT(year from dt)*100        + EXTRACT(month from dt) as year_month_id,
  EXTRACT(year from fiscal_dt)*100 + EXTRACT(month from fiscal_dt) as fiscal_year_month_id,
  to_char(dt, 'YYYY')        || ' Q' || to_char(dt, 'Q') as quarter,
  to_char(fiscal_dt, 'YYYY') || ' Q' || to_char(fiscal_dt, 'Q') as fiscal_quarter
  --, EXTRACT(day from dt) as day_of_month, to_char(dt, 'YYYY-WW') as week_of_year, to_char(dt, 'D') as day_of_week
  FROM (
    SELECT dt, add_months(dt, 6) as fiscal_dt --starts July 1st
    FROM (
      SELECT TO_DATE('12/31/1996', 'mm/dd/yyyy') + ROWNUM as dt 
      FROM DUAL CONNECT BY ROWNUM < 366 * 30 --30 years
    )
    WHERE dt <= TO_DATE('12/31/2020', 'mm/dd/yyyy')
  )

答案 7 :(得分:2)

Ahahaha,这是一个有趣的方式,我想出来这样做:

select SYSDATE - ROWNUM
from shipment_weights sw
where ROWNUM < 365;

其中shipment_weights是任何大表;

答案 8 :(得分:2)

我有同样的要求 - 我只是用它。用户输入他/她想要将日历范围限制为的天数。

  SELECT DAY, offset
    FROM (SELECT to_char(SYSDATE, 'DD-MON-YYYY') AS DAY, 0 AS offset
            FROM DUAL
          UNION ALL
          SELECT to_char(SYSDATE - rownum, 'DD-MON-YYYY'), rownum
            FROM all_objects d)
            where offset <= &No_of_days

我将上述结果集用作LEFT OUTER JOIN中的驾驶视图,其他视图涉及具有日期的表格。

答案 9 :(得分:2)

从6个月前的一周

SELECT (date'2015-08-03' + (LEVEL-1)) AS DATES
 FROM DUAL 
 where ROWNUM < 8
 connect by level <= (sysdate-date'2015-08-03'); 

如果省略ROWNUM,则只能获得50行,与值无关。

答案 10 :(得分:1)

为了它的乐趣,这里有一些应该在SQL Server,Oracle或MySQL中运行的代码:

SELECT current_timestamp - CAST(d1.digit + d2.digit + d3.digit as int)
FROM 
(
    SELECT digit
    FROM
    (
        select '1' as digit
        union select '2'
        union select '3'
        union select '4'
        union select '5'
        union select '6'
        union select '7'
        union select '8'
        union select '9'
        union select '0'
    ) digits
) d1
CROSS JOIN
(
    SELECT digit
    FROM
    (
        select '1' as digit
        union select '2'
        union select '3'
        union select '4'
        union select '5'
        union select '6'
        union select '7'
        union select '8'
        union select '9'
        union select '0'
    ) digits
) d2
CROSS JOIN
(
    SELECT digit
    FROM
    (
        select '1' as digit
        union select '2'
        union select '3'
        union select '4'
        union select '5'
        union select '6'
        union select '7'
        union select '8'
        union select '9'
        union select '0'
    ) digits
) d3
WHERE CAST(d1.digit + d2.digit + d3.digit as int) < 365
ORDER BY d1.digit, d2.digit, d3.digit -- order not really needed here
如果你能给我一个跨平台的语法来重复使用数字表,那么

奖励积分。

答案 11 :(得分:1)

迟到总比不到好。这是我设计的一种方法(阅读此文章后),用于返回日期列表,其中包括:(a)直到今天的当月第一天,再加上(b)过去两个月的所有日期:

select (sysdate +1 - rownum) dt 
from dual 
 connect by rownum <= (sysdate - add_months(sysdate - extract(day from sysdate),-2));

“-2”是要包含的前一个完整月的日期数。例如,在7月10日,此SQL返回5月1日至7月10日的所有日期的列表-即前两个完整月份加上当前的部分月份。

答案 12 :(得分:1)

从今天起365天的另一种简单方法是:

sequenceA

答案 13 :(得分:0)

我没有重复使用数字表的答案,但这里的代码示例至少可以在SQL服务器中运行,并且速度更快。

print("code sample");

select  top 366 current_timestamp - row_number() over( order by l.A * r.A) as DateValue
from (
select  1 as A union
select  2 union
select  3 union
select  4 union
select  5 union
select  6 union
select  7 union
select  8 union
select  9 union
select  10 union
select  11 union
select  12 union
select  13 union
select  14 union
select  15 union
select  16 union
select  17 union
select  18 union
select  19 union
select  20 union
select  21 
) l
cross join (
select 1 as A union
select 2 union
select 3 union
select 4 union
select 5 union
select 6 union
select 7 union
select 8 union
select 9 union
select 10 union
select 11 union
select 12 union
select 13 union
select 14 union
select 15 union
select 16 union
select 17 union
select 18
) r
print("code sample");

答案 14 :(得分:0)

此查询会生成未来4000天的日期列表和截至今天的5000个日期列表(受http://blogs.x2line.com/al/articles/207.aspx启发):

SELECT * FROM (SELECT
    (CONVERT(SMALLDATETIME, CONVERT(CHAR,GETDATE() ,103)) + 4000 -
                n4.num * 1000 -
                n3.num * 100 -
                n2.num * 10 -
                n1.num) AS Date, 
    year(CONVERT(SMALLDATETIME, CONVERT(CHAR,GETDATE() ,103)) + 4000 -
                n4.num * 1000 -
                n3.num * 100 -
                n2.num * 10 -
                n1.num) as Year,
    month(CONVERT(SMALLDATETIME, CONVERT(CHAR,GETDATE() ,103)) + 4000 -
                n4.num * 1000 -
                n3.num * 100 -
                n2.num * 10 -
                n1.num) as Month,
    day(CONVERT(SMALLDATETIME, CONVERT(CHAR,GETDATE() ,103)) + 4000 -
                n4.num * 1000 -
                n3.num * 100 -
                n2.num * 10 -
                n1.num) as Day
           FROM (SELECT 0 AS num union ALL
                 SELECT 1 UNION ALL
                 SELECT 2 UNION ALL
                 SELECT 3 UNION ALL
                 SELECT 4 UNION ALL
                 SELECT 5 UNION ALL
                 SELECT 6 UNION ALL
                 SELECT 7 UNION ALL
                 SELECT 8 UNION ALL
                 SELECT 9) n1
               ,(SELECT 0 AS num UNION ALL
                 SELECT 1 UNION ALL
                 SELECT 2 UNION ALL
                 SELECT 3 UNION ALL
                 SELECT 4 UNION ALL
                 SELECT 5 UNION ALL
                 SELECT 6 UNION ALL
                 SELECT 7 UNION ALL
                 SELECT 8 UNION ALL
                 SELECT 9) n2
               ,(SELECT 0 AS num union ALL
                 SELECT 1 UNION ALL
                 SELECT 2 UNION ALL
                 SELECT 3 UNION ALL
                 SELECT 4 UNION ALL
                 SELECT 5 UNION ALL
                 SELECT 6 UNION ALL
                 SELECT 7 UNION ALL
                 SELECT 8 UNION ALL
                 SELECT 9) n3  
               ,(SELECT 0 AS num UNION ALL
                 SELECT 1 UNION ALL
                 SELECT 2 UNION ALL
                 SELECT 3 UNION ALL
                 SELECT 4 UNION ALL
                 SELECT 5 UNION ALL
                 SELECT 6 UNION ALL
                 SELECT 7 UNION ALL
                 SELECT 8) n4
        ) GenCalendar  ORDER BY 1

答案 15 :(得分:0)

我经常为我工作的调度应用程序执行此操作,因此我创建了一个流水线表函数。有时我需要几天、几小时或 15 分钟的时间间隔。这与我使用的功能不完全相同,因为我的代码在一个包中。但是,在这里,我在 2020 年 1 月 1 日和 2020 年 1 月 10 日之间有几天:

SELECT
    days.date_time
FROM
    table(between_times(TO_DATE('2020-01-01'),TO_DATE('2020-01-10'),(60*24), 'Y')) days

流水线函数:

function between_times(i_start_time TIMESTAMP, i_end_time TIMESTAMP, i_interval_in_minutes NUMBER, include_end_time VARCHAR2 := 'N')
  RETURN DateTableType  PIPELINED
  AS
    time_counter TIMESTAMP := i_start_time;
  BEGIN
    IF i_start_time IS NULL OR i_end_time IS NULL or i_start_time > i_end_time OR i_interval_in_minutes IS NULL OR
      i_interval_in_minutes <= 0 THEN
        RETURN;
      END IF;
      LOOP

        -- by default does not include end time
        if (include_end_time = 'Y') THEN
          exit when time_counter > i_end_time;
        ELSE
          exit when time_counter >= i_end_time;
        END IF;
        
        
        pipe row(DateType( time_counter ));     
        time_counter := time_counter + i_interval_in_minutes/(60*24);
        
      END LOOP;
      
      EXCEPTION  WHEN NO_DATA_NEEDED THEN NULL;      
  END;