2

我有一些带有时间戳的记录的 PostgreSQL 数据库。

是否有简单的方法在一段时间内(例如一个月,使用 PRECEDING 和 FOLLOWING 表达式)收集窗口中的数据,然后创建包含本月所有记录的多列(例如,每月每天 30 列)?

让我们考虑这个简单的情况:一个包含两列timestampmeasurement. 我想要的是获得31 列的表:时间戳和measurement1measurement2... measurement30measurement_i时间戳前 i 天的测量值在哪里。

4

1 回答 1

1

如果您希望结果中有多个这样的行,我会使用一个crosstab()函数。

但根据你的描述,你想要一个单行。我会用窗口函数lead()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;

-> sqlfiddle

于 2013-02-19T16:58:48.903 回答