2015-11-12 2 views
0

Я работаю с базой данных Vertica, и мне нужно было сделать запрос, который, учитывая две даты, предоставит мне список всех месяцев между указанными датами. Например, если бы я, чтобы дать запрос 2015-01-01 и 2015-12-31, он будет выводить меня следующий список:Вертикальная дата-серия начинается за месяц до указанной даты

2015-01-01 
2015-02-01 
2015-03-01 
2015-04-01 
2015-05-01 
2015-06-01 
2015-07-01 
2015-08-01 
2015-09-01 
2015-10-01 
2015-11-01 
2015-12-01 

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

SELECT date_trunc('MONTH', ts)::date as Mois 
FROM 
(
    SELECT '2015-01-01'::TIMESTAMP as tm 
    UNION 
    SELECT '2015-12-31'::TIMESTAMP as tm 
) as t 
TIMESERIES ts as '1 month' OVER (ORDER BY tm) 

Этот запрос работает и дает мне следующий вывод:

2014-12-01 
2015-01-01 
2015-02-01 
2015-03-01 
2015-04-01 
2015-05-01 
2015-06-01 
2015-07-01 
2015-08-01 
2015-09-01 
2015-10-01 
2015-11-01 
2015-12-01 

Как вы можете видеть, давая запрос, отправную дату «2015-01-01» или где-нибудь в январе для этого важно, чтобы я закончил с ext ra, а именно 2014-12-01. Сама по себе ошибка (или то, что вы хотите назвать этим неожиданным поведением) легко обойти (только начать в феврале), но я должен признать, что мой любопытство покорился. Почему именно сериал начинается через месяц до даты, указанной мной?

EDIT: Хорошо, прочитав предупреждение Кимбо и подтвердив, что действительно, длительные периоды в конечном итоге вызовут проблемы, я смог выработать следующий запрос, который правильно корректирует даты.

SELECT ts as originalMonth, 
ts + 
    (
     mod 
     (
      day(first_value(ts) over (order by ts)) - day(ts) + day(last_day(ts)), 
      day(last_day(ts)) 
     ) 
    ) as adjustedMonth 
FROM 
(
    SELECT ts 
    FROM 
    (
     SELECT '2015-01-01'::TIMESTAMP as tm 
     UNION 
     SELECT '2018-12-31'::TIMESTAMP as tm 
    ) as t 
    TIMESERIES ts as '1 month' OVER (ORDER BY tm) 
) as temp 

Единственная проблема у меня есть, что я не имею никакого контроля над начальным днем ​​первой записи серии. Он устанавливается автоматически Vertica в текущий день. Поэтому, если я запустил этот запрос 31-го числа месяца, мне интересно, как он будет себя вести. Думаю, мне просто нужно ждать декабря, если кто-то не знает, как заставить таймеры вести себя таким образом, чтобы я мог ее протестировать.

EDIT: Хорошо, поэтому, опробовав множество разных комбинаций дат, я смог определить, что день, который начинается в серии, зависит от указанной вами даты. Это вызвало массу проблем ... пока мы не решили пойти простым путем. Вместо использования месячного интервала мы использовали дневной интервал и выбирали только один конкретный день в месяц. ПУТЬ проще, и он работает все время. Вот окончательный запрос:

SELECT ts as originalMonth 
FROM 
(
    SELECT ts 
    FROM 
    (
     SELECT '2000-02-01'::TIMESTAMP as tm 
     UNION 
     SELECT '2018-12-31'::TIMESTAMP as tm 
    ) as t 
    TIMESERIES ts as '1 day' OVER (ORDER BY tm) 
) as temp 
where day(ts) = 1 
+0

Вы должны создать [таблицу календаря] (http://vertica.tips/2014/07/17/creating-a-numbers-and-calendar-table/), в противном случае доступно SQL-решение [здесь] (http://vertica-forums.com/viewtopic.php?p=7223#p7223). – Kermit

+0

Спасибо Кермит, но это было не то, о чем я просил. Я спрашивал о дополнительном «2014-12-01», который появляется в начале списка. Как бы то ни было, проблема, вызвавшая необходимость создания этого запроса, уже решена. – Osuwariboy

ответ

3

Я думаю, что это сводится к этому заявлению от Doc: http://my.vertica.com/docs/7.1.x/HTML/index.htm#Authoring/SQLReferenceManual/Statements/SELECT/TIMESERIESClause.htm

TIME_SLICE может вернуть время начала или окончания кванта времени, в зависимости от значения его четвертый входной параметр (start_or_end). TIMESERIES, , с другой стороны, всегда возвращает время начала каждого временного фрагмента.

При определении временного интервала с некоторой начальной датой (2015-01-01, например), то TIMESERIES ts AS '1 month' создаст для своего первого временного отрезка куска, который начинается 1 месяц до этой первой точки данных, так 2014-12-01. Когда вы делаете DATE_TRUNC('MON', ts), это, конечно, устанавливает первое значение даты 2014-12-01, даже если ваша дата начала равна 2015-01-03 или что-то еще.

e: Я хочу выслать еще одно предупреждение - ваше использование DATE_TRUNC достигает того, что вам нужно, я думаю. Но из документа: В отличие от TIME_SLICE, длина и длина единицы времени, выраженная в [TIMESERIES] length_and_time_unit_expr, должны быть константами, так что зазоры во временных срезах четко определены. Это означает, что «1 месяц» на самом деле составляет 30 дней. У этого, очевидно, есть проблемы, если вы собираетесь больше, чем через пару лет.

Смежные вопросы