我有一些PostgreSQL数据库,其中包含一些带有时间戳的记录。
是否有简单的方法在一段时间内(例如,一个月,使用PRECEDING和FOLLOWING表达式)在窗口中收集数据,然后创建多个列(例如,每月每天30个),其中包含本月的所有记录?
让我们考虑这个简单的案例:包含两列timestamp
和measurement
的表格。
我想要的是获得31列的表:时间戳和measurement1
,measurement2
... measurement30
,其中measurement_i
是测量i天在时间戳之前。
答案 0 :(得分:1)
如果你想在结果中使用多行,我会使用crosstab()
函数。
但根据您的描述,您需要单行。我会用window functions lead()
or lag()
解决这个问题
主要技巧是在应用WHERE子句之前使用子查询或CTE生成所有列,并将结果缩小到单行。我会在这里使用CTE:
给出下表(您应该提供的):
CREATE TABLE tbl(
tbl_id serial PRIMARY KEY
,ts timestamp NOT NULL
,value int
);
查询可能如下所示:
WITH x AS (
SELECT tbl_id, ts, value
,lag(value, 1) OVER w AS value_day_before_1
,lag(value, 2) OVER w AS value_day_before_2
-- ...
,lead(value, 1) OVER w AS value_day_after_1
,lead(value, 2) OVER w AS value_day_after_2
-- ...
FROM tbl
WINDOW w AS (ORDER BY ts)
)
SELECT *
FROM x
WHERE ts = '2013-02-14 0:0'::timestamp
时间戳也可以是白天的任何时间。
生成包含generate_series()
和LEFT JOIN
表格的日期列表:
WITH x AS (
SELECT tbl_id, ts, value
,lag(value, 1) OVER w AS value_day_before_1
,lag(value, 2) OVER w AS value_day_before_2
-- ...
,lead(value, 1) OVER w AS value_day_after_1
,lead(value, 2) OVER w AS value_day_after_2
-- ...
FROM (
SELECT generate_series ('2013-02-01'::date
,'2013-02-28'::date
,interval '1d') AS day
) d
LEFT JOIN tbl t ON date_trunc('day', t.ts) = d.day
WINDOW w AS (ORDER BY day)
)
SELECT *
FROM x
WHERE ts = '2013-02-14 0:0'::timestamp;