我有一个这样的查询,很好地生成了两个给定日期之间的一系列日期:
select date '2004-03-07' + j - i as AllDate
from generate_series(0, extract(doy from date '2004-03-07')::int - 1) as i,
generate_series(0, extract(doy from date '2004-08-16')::int - 1) as j
它会在2004-03-07
和2004-08-16
之间生成162个日期,这就是我想要的。此代码的问题在于,当两个日期来自不同年份时,例如当我尝试2007-02-01
和2008-04-01
时,它无法给出正确的答案。
有更好的解决方案吗?
答案 0 :(得分:113)
可以在不转换为/从int转换的情况下完成(但是转换为/来自时间戳)
SELECT date_trunc('day', dd):: date
FROM generate_series
( '2007-02-01'::timestamp
, '2008-04-01'::timestamp
, '1 day'::interval) dd
;
答案 1 :(得分:41)
这应该是 最佳 方式:
SELECT day::date
FROM generate_series(timestamp '2004-03-07'
, timestamp '2004-08-16'
, interval '1 day') AS t(day);
不需要额外的date_trunc()
。对date
(day::date
)的强制转换是隐含的。
但将日期文字转换为date
作为输入参数也没有意义。相反, timestamp
是最佳选择。性能的优势很小,但没有理由不采取它。并且您不必毫不涉及DST(夏令时)规则以及从date
到timestamp with time zone
并返回的转换。见下文。
等效的短语法:
SELECT day::date
FROM generate_series(timestamp '2004-03-07', '2004-08-16', '1 day') day;
或使用SELECT
列表中的set-returns函数:
SELECT generate_series(timestamp '2004-03-07', '2004-08-16', '1 day')::date AS day;
最后一个版本中AS
关键字必需,否则Postgres会误解列别名day
。而且我会在Postgres 10之前不建议该变体 - 至少在同一个SELECT
列表中没有多个set-returns函数:
generate_series()
有许多重载变体。目前(Postgres 11):
SELECT oid::regprocedure AS function_signature , prorettype::regtype AS return_type FROM pg_proc where proname = 'generate_series';
function_signature | return_type :-------------------------------------------------------------------------------- | :-------------------------- generate_series(integer,integer,integer) | integer generate_series(integer,integer) | integer generate_series(bigint,bigint,bigint) | bigint generate_series(bigint,bigint) | bigint generate_series(numeric,numeric,numeric) | numeric generate_series(numeric,numeric) | numeric generate_series(timestamp without time zone,timestamp without time zone,interval) | timestamp without time zone generate_series(timestamp with time zone,timestamp with time zone,interval) | timestamp with time zone
(Postgres 9.5添加了numeric
个变体。)相关的变体是最后两个以粗体显示并且返回timestamp
/ timestamptz
。< / p>
正如您所看到的,没有变体采取或返回date
。返回date
需要显式强制转换。传递timestamp
直接解析为最佳变体,而不会降低到函数类型解析规则,也无需为输入添加额外的强制转换。
timestamp '2004-03-07'
完全有效,顺便说一下。省略的时间部分默认为00:00
,具有ISO格式。
感谢function type resolution,我们仍然可以通过date
。但这需要Postgres的更多工作。从date
到timestamp
以及从date
到timestamptz
都有一个 隐式强制强制。不明确,但“日期/时间类型”中timestamptz
“首选”。所以match is decided at step 4d.:
贯穿所有候选人并保留那些接受首选类型的候选人 (输入数据类型的类型类别)在大多数位置 将需要类型转换。如果不接受,请保留所有候选人 首选类型。如果只剩下一名候选人,请使用它;否则继续 到下一步。
除了函数类型解析中的额外工作外,这还为timestamptz
添加了额外的强制转换。对timestamptz
的强制转换不仅增加了成本,而且还会引入DST问题,在极少数情况下会导致意外结果。 (DST是一个愚蠢的概念,顺便说一句,不能强调这一点。)相关:
我将演示添加到小提琴中,显示更昂贵的查询计划:
dbfiddle here
相关:
答案 2 :(得分:32)
您可以直接生成日期系列。无需使用整数或时间戳:
select date::date
from generate_series(
'2004-03-07'::date,
'2004-08-16'::date,
'1 day'::interval
) date;
答案 3 :(得分:0)
您可以使用like
select generate_series('2012-12-31':: timestamp,'2018-10-31':: timestamp,'1 day':: interval)::日期