f.a*_*uri 72 postgresql date time-series postgresql-9.1 generate-series
我有这样的查询,很好地生成两个给定日期之间的一系列日期:
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
Run Code Online (Sandbox Code Playgroud)
它在2004-03-07和之间生成162个日期2004-08-16,这就是我想要的.这段代码的问题是,它不会得到正确的答案时,这两个日期都不同年份,例如,当我尝试2007-02-01和2008-04-01.
有更好的解决方案吗?
wil*_*ser 129
可以在不转换为/从int转换的情况下完成(但是转换为/从时间戳转换)
SELECT date_trunc('day', dd):: date
FROM generate_series
( '2007-02-01'::timestamp
, '2008-04-01'::timestamp
, '1 day'::interval) dd
;
Run Code Online (Sandbox Code Playgroud)
Erw*_*ter 54
有两个答案(到目前为止).两者都有效,但两者都不是最理想的.这是第三个:
SELECT t.day::date
FROM generate_series(timestamp '2004-03-07'
, timestamp '2004-08-16'
, interval '1 day') AS t(day);
Run Code Online (Sandbox Code Playgroud)
无需额外的date_trunc().强制转换为date(day::date).
但是将日期文字转换date为输入参数也没有意义.Au逆转,timestamp是这里的最佳选择.性能的优势很小,但没有理由不采取它.并且你不必不必要地涉及与数据类型相结合的DST规则date.见下面的解释.
更短的等价物:
SELECT day::date
FROM generate_series(timestamp '2004-03-07', '2004-08-16', '1 day') day;
Run Code Online (Sandbox Code Playgroud)
或者甚至使用timestamp with time zone列表中的set-returns函数:
SELECT generate_series(timestamp '2004-03-07', '2004-08-16', '1 day')::date AS day;
Run Code Online (Sandbox Code Playgroud)
该SELECT关键字要求在这里,因为列别名AS否则会被误解.
我不建议在Postgres 10之前使用最后一个,至少在同一个day列表中没有多个set-returns函数.看到:
有许多重载的变种SELECT.目前(Postgres 10):
Run Code Online (Sandbox Code Playgroud)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
timestamp [without time zone]Postgres 9.5添加了变换和返回.但这里相关的唯一因素是最后两个粗体回吐和返回generate_series()/ numeric.
如您所见,没有变体采取或返回timestamp.这就是为什么我们想要返回时需要一个明确的演员timestamptz.date直接将解析传递给正确的函数,而不必下载到函数类型解析规则中,也不需要为输入添加额外的强制转换.
并且date完全有效.timestamp如果省略,则时间部分默认为.
由于功能类型分辨率,我们仍然可以通过timestamp '2004-03-07'.但这需要Postgres的更多工作.有一个隐含的投从00:00到date以及从date到timestamp.将是模棱两可的,但在"日期/时间类型"中date是"首选 ".所以匹配在步骤4d决定.:
运行所有候选项并将接受首选类型(输入数据类型的类型类别)的那些保留在需要进行类型转换的大多数位置.如果没有接受首选类型,请保留所有候选 如果只剩下一名候选人,请使用它; 否则继续下一步.
除了函数类型解析的额外工作之外,还增加了额外的强制转换timestamptz.演员timestamptz不仅增加了成本,还会引入夏令时(DST)问题,在极少数情况下会导致意外结果.(DST是一个愚蠢的概念,顺便说一句,不能强调这一点.)相关:
我向小提琴添加了演示,以显示更昂贵的查询计划:
dbfiddle 在这里
有关:
fbo*_*tti 33
您可以直接生成日期系列.无需使用整数或时间戳:
select date::date
from generate_series(
'2004-03-07'::date,
'2004-08-16'::date,
'1 day'::interval
) date;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
67997 次 |
| 最近记录: |