Vertica 日期系列在指定日期前一个月开始
Vertica date series is starting one month before specified date
我使用 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”的开始日期或一月份的任何时间,我最终得到了一个额外的条目,即 2014-12-01。就其本身而言,该错误(或任何您想称呼这种意外行为的名称)很容易规避(从 2 月开始),但我不得不承认我的好奇心被激怒了。为什么系列赛比我指定的日期早一个月开始?
编辑:好吧,在阅读了 Kimbo 的警告并确认确实,长时间最终会导致问题之后,我能够提出以下正确重新调整日期的查询。
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 日 运行 这个查询,我想知道它会如何表现。我想我只能等到 12 月才能看到,除非有人知道如何让时间序列以允许我测试它的方式运行。
编辑:好的,在尝试了许多不同的日期组合之后,我能够确定系列开始的日期会根据您指定的日期而变化。这导致了很多问题……直到我们决定采用简单的方法。我们没有使用月间隔,而是使用天间隔并且每月只选择一个特定的日子。方式更简单,它一直有效。这是最终查询:
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
我认为这可以归结为文档中的这个声明:http://my.vertica.com/docs/7.1.x/HTML/index.htm#Authoring/SQLReferenceManual/Statements/SELECT/TIMESERIESClause.htm
TIME_SLICE can return the start or end time of a time slice, depending
on the value of its fourth input parameter (start_or_end). TIMESERIES
,
on the other hand, always returns the start time of each time slice.
当您定义一个具有某个开始日期的时间间隔(例如 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 天。如果你要用几年以上,这显然会有问题。
我使用 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”的开始日期或一月份的任何时间,我最终得到了一个额外的条目,即 2014-12-01。就其本身而言,该错误(或任何您想称呼这种意外行为的名称)很容易规避(从 2 月开始),但我不得不承认我的好奇心被激怒了。为什么系列赛比我指定的日期早一个月开始?
编辑:好吧,在阅读了 Kimbo 的警告并确认确实,长时间最终会导致问题之后,我能够提出以下正确重新调整日期的查询。
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 日 运行 这个查询,我想知道它会如何表现。我想我只能等到 12 月才能看到,除非有人知道如何让时间序列以允许我测试它的方式运行。
编辑:好的,在尝试了许多不同的日期组合之后,我能够确定系列开始的日期会根据您指定的日期而变化。这导致了很多问题……直到我们决定采用简单的方法。我们没有使用月间隔,而是使用天间隔并且每月只选择一个特定的日子。方式更简单,它一直有效。这是最终查询:
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
我认为这可以归结为文档中的这个声明:http://my.vertica.com/docs/7.1.x/HTML/index.htm#Authoring/SQLReferenceManual/Statements/SELECT/TIMESERIESClause.htm
TIME_SLICE can return the start or end time of a time slice, depending on the value of its fourth input parameter (start_or_end).
TIMESERIES
, on the other hand, always returns the start time of each time slice.
当您定义一个具有某个开始日期的时间间隔(例如 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 天。如果你要用几年以上,这显然会有问题。