显示具有多列的单行中多行的数据

时间:2013-02-19 10:47:55

标签: sql postgresql crosstab window-functions

我有一些PostgreSQL数据库,其中包含一些带有时间戳的记录。

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

让我们考虑这个简单的案例:包含两列timestampmeasurement的表格。 我想要的是获得31列的:时间戳和measurement1measurement2 ... measurement30,其中measurement_i是测量i天在时间戳之前。

1 个答案:

答案 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;

->sqlfiddle