Генерация диапазона дат с использованием SQL - PullRequest
26 голосов
/ 07 января 2009

У меня есть SQL-запрос, который принимает параметр даты (если бы я бросил его в функцию), и мне нужно запускать его каждый день прошлого года.

Как создать список за последние 365 дней, чтобы я мог использовать прямой SQL для этого?

Очевидно, что генерация списка 0..364 тоже подойдет, так как я всегда мог:

SELECT SYSDATE - val FROM (...);

Ответы [ 14 ]

80 голосов
/ 07 января 2009

Нет необходимости использовать очень большие таблицы или таблицу ALL_OBJECTS:

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

сделает свое дело.

9 голосов
/ 11 августа 2011
 SELECT (sysdate-365 + (LEVEL -1)) AS DATES
 FROM DUAL connect by level <=( sysdate-(sysdate-365))

если вместо sysdate и sysdate-365 заменить дату «от» и дату «до», результатом будет диапазон дат от даты до даты.

6 голосов
/ 05 мая 2015

Недавно у меня возникла похожая проблема, и я решил ее с помощью простого запроса:

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 голосов
/ 04 мая 2017

Диапазон дат между 31.12.1996 и 12/31/20020

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')
  )
3 голосов
/ 26 августа 2010

Примерно на полтора года слишком поздно, но для потомков есть версия для Teradata:

SELECT calendar_date 
FROM SYS_CALENDAR.Calendar
WHERE SYS_CALENDAR.Calendar.calendar_date between '2010-01-01' (date) and '2010-01-03' (date)
3 голосов
/ 07 января 2009

Метод, довольно часто используемый в Oracle, выглядит примерно так:

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

Лично, если приложению нужен список дат, я бы просто создал таблицу с ними, или создал бы таблицу с серией целых чисел до чего-то смешного, например, миллион, который можно использовать для такого рода вещи.

3 голосов
/ 07 января 2009

Специфично для 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
2 голосов
/ 23 февраля 2016

Неделя с 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 строк, независимо от значения.

2 голосов
/ 17 апреля 2014

У меня было такое же требование - я просто использую это. Пользователь вводит количество дней, на которое он / она хочет ограничить диапазон календаря, до.

  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 с другими представлениями, включающими таблицы с датами.

2 голосов
/ 07 января 2009

Ахахаха, вот забавный способ, которым я только что придумал:

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

где shipment_weights - любая большая таблица;

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...