Postgres行到列

时间:2014-02-07 11:27:31

标签: sql postgresql pivot crosstab

我已经阅读了很多关于如何“转置”或转移数据的问题,但是没有什么能让我看到我想做的事情是否可能。

在Postgres表中给出一组数据,如下所示:

issue       valid       station     value
2013-02-01  2013-02-01  A           1
2013-02-01  2013-02-02  A           1.2
2013-02-01  2013-02-03  A           1.3
2013-02-01  2013-02-04  A           1.0
2013-02-01  2013-02-01  B           2.1
2013-02-01  2013-02-02  B           2.1
2013-02-01  2013-02-03  B           2.4
2013-02-01  2013-02-04  B           2.7
2013-02-01  2013-02-01  C           3.2
2013-02-01  2013-02-02  C           3.7
2013-02-01  2013-02-03  C           3.5
2013-02-01  2013-02-04  C           3.5

我希望能够查询如果我设置issue=2013-02-01会导致:

station  val_day1  day1        val_day1  day2        val_day3  day3        val_day4  day4        max_val
A        1         2013-02-01  1.2       2013-02-02  1.3       2013-02-03  1.0       2013-02-04  1.3     
B        2.1       2013-02-01  2.1       2013-02-02  2.4       2013-02-03  2.7       2013-02-04  2.7 
C        3.2       2013-02-01  3.7       2013-02-02  3.5       2013-02-03  3.5       2013-02-04  3.7

不幸的是,我对自己可以改变的内容非常有限,所以如果可以在一个很棒的SQL查询中解决这个问题。

对于每个问题,数据始终有4天不同的“有效”日期。每天都会增加一个新问题。

这甚至可以尝试在Postgres开始吗?

由于

1 个答案:

答案 0 :(得分:1)

您可以使用CASE和MAX组合来转动数据:

select v2.station, 
  max(day1) as day1,
  max(val_day1) as val_day1,
  max(day2) as day2,
  max(val_day2) as val_day2,
  max(day3) as day3,
  max(val_day3) as val_day3,
  max(day4) as day4,
  max(val_day4) as val_day4,
  max(greatest(val_day1, val_day2, val_day3, val_day4)) as max_val
from (
select v1.*, 
  (case when v1.day = 1 then v1.valid else NULL end) as day1,
  (case when v1.day = 1 then v1.value else NULL end) as val_day1,
  (case when v1.day = 2 then v1.valid else NULL end) as day2,
  (case when v1.day = 2 then v1.value else NULL end) as val_day2,
  (case when v1.day = 3 then v1.valid else NULL end) as day3,
  (case when v1.day = 3 then v1.value else NULL end) as val_day3,
  (case when v1.day = 4 then v1.valid else NULL end) as day4,
  (case when v1.day = 4 then v1.value else NULL end) as val_day4
from
(select t.valid, t.station, t.value, t.valid - t.issue +1 as day
from so_data t) v1
  ) v2
group by v2.station
order by v2.station

SQL Fiddle