Postgres中的Generate_series从表中的开始和结束日期开始

Sir*_*its 7 sql postgresql aggregate-functions generate-series

我一直在尝试从时间戳字段中的第一个日期到最后一个日期生成一系列日期(YYYY-MM-DD HH).我有generate_series()我需要的东西,但是在尝试从表中获取开始和结束日期时遇到了问题.我有以下几点给出一个粗略的想法:

with date1 as
(
SELECT start_timestamp as first_date
FROM header_table
ORDER BY start_timestamp DESC
LIMIT 1
),
date2 as
(
SELECT start_timestamp as first_date
FROM header_table
ORDER BY start_timestamp ASC    
LIMIT 1
)
    select generate_series(date1.first_date, date2.first_date
                         , '1 hour'::interval)::timestamp as date_hour

from
(   select * from date1
    union
    select * from date2) as foo
Run Code Online (Sandbox Code Playgroud)

Postgres 9.3

Erw*_*ter 19

你肯定不会需要一个CTE这一点.那将比必要的更昂贵.
并且您不需要转换为,timestamp因为在将类型提供给时,结果已经数据类型.timestampdategenerate_series()

在Postgres 9.3或更高版本中,通过LATERAL连接最优雅地解决了这个问题:

SELECT to_char(ts, 'YYYY-MM-DD HH24') AS formatted_ts
FROM  (
   SELECT min(start_timestamp) as first_date
        , max(start_timestamp) as last_date
   FROM   header_table
   ) h
  , generate_series(h.first_date, h.last_date, interval '1 hour') g(ts);
Run Code Online (Sandbox Code Playgroud)

(可选)以to_char()您提到的格式将结果作为文本获取.
在早期(或任何)版本中:

SELECT generate_series(min(start_timestamp)
                     , max(start_timestamp)
                     , interval '1 hour') AS ts
FROM   header_table;
Run Code Online (Sandbox Code Playgroud)

但是在SELECT列表中调用set-returns函数是一个非标准的功能,并且有些人不赞成.如果可以,请使用第一个查询.

注意NULL处理的细微差别:

相当于

max(start_timestamp)
Run Code Online (Sandbox Code Playgroud)

得到了

ORDER BY start_timestamp DESC NULLS LAST
LIMIT 1
Run Code Online (Sandbox Code Playgroud)

没有NULLS LASTNULL值首先按降序排列(如果可以有NULL值start_timestamp).你会得到NULL last_date,你的查询将是空的.

细节:


Gor*_*off 5

改用聚合函数怎么样?

with dates as (
      SELECT min(start_timestamp) as first_date, max(start_timestamp) as last_date
      FROM header_table
     )
select generate_series(first_date, last_date, '1 hour'::interval)::timestamp as date_hour
from dates;
Run Code Online (Sandbox Code Playgroud)

甚至:

select generate_series(min(start_timestamp),
                       max(start_timestamp),
                       '1 hour'::interval
                      )::timestamp as date_hour
from header_table;
Run Code Online (Sandbox Code Playgroud)