在Postgres中查询时间序列表的最后一个非空值

时间:2019-11-30 21:11:57

标签: sql postgresql time-series

我有一个时序表,如下所示:

time                |   a     | b        | c       | d
--------------------+---------+----------+---------+---------
2016-05-15 00:08:22 |         |          |         |         
2016-05-15 01:50:56 |         |          | 26.8301 |
2016-05-15 02:41:58 |         |          |         |            
2016-05-15 03:01:37 |         |          |         |            
2016-05-15 04:45:18 |         |          |         |         
2016-05-15 05:45:32 |         |          | 26.9688 |
2016-05-15 06:01:48 |         |          |         |         
2016-05-15 07:47:56 |         |          |         | 27.1269
2016-05-15 08:01:22 |         |          |         |            
2016-05-15 09:35:36 | 26.7441 | 29.8398  |         | 26.9981
2016-05-15 10:08:53 |         |          |         |         
2016-05-15 11:08:30 |         |          |         |         
2016-05-15 12:14:59 |         |          |         |         
2016-05-15 13:33:36 | 27.4277 | 29.7695  |         |                            
2016-05-15 14:36:36 | 27.4688 | 29.6836  |         |            
2016-05-15 15:37:36 | 27.1016 |          |         |       

我想返回每列的最后一个非空值:

像这样(最佳选择):

time                | column   | value
--------------------+--------- +-------
2016-05-15 15:37:36 | a        | 27.1016
2016-05-15 14:36:36 | b        | 29.6836
2016-05-15 05:45:32 | c        | 26.9688
2016-05-15 09:35:36 | d        | 26.9981

像这样:

column   | value
-------- +-------
a        | 27.1016
b        | 29.6836
c        | 26.9688
d        | 26.9981

或至少像这样:

a       | b        | c       | d
--------+----------+---------+---------
27.1016 | 29.6836  | 26.9688 | 26.9981

谢谢!

2 个答案:

答案 0 :(得分:2)

您可以取消透视并选择最后一行:

select distinct on (v.which) t.time, v.which, v.val
from t cross join lateral
     (values (a, 'a'), (b, 'b'), (c, 'c'), (d, 'd')) v(val, which)
where v.val is not null
order by v.which, t.time desc;

答案 1 :(得分:1)

我建议另一个答案,但是现在我看到@GordonLinoff的答案更好。

with src as (
  select '0' as pos,    1    as a, 2    as b, null as c
  union all select '1', null as a, null as b, 7    as c
  union all select '2', 2    as a, null as b, 3    as c
  union all select '3', null as a, null as b, null as c
  union all select '4', null as a, 4    as b, null as c
),
n as (
 select row_number() over() as rn, src.* from src
)

(select last_value(pos) over (order by rn desc) as timestamp, 'a' as column, last_value(a) over (order by rn desc) as value 
from n
where a is not null
limit 1)
union all
(select last_value(pos) over (order by rn desc) as timestamp, 'b' as column, last_value(b) over (order by rn desc) as value 
from n
where b is not null
limit 1)
union all
(select last_value(pos) over (order by rn desc) as timestamp, 'c' as column, last_value(c) over (order by rn desc) as value 
from n
where c is not null
limit 1)
timestamp | column | value
:-------- | :----- | ----:
2         | a      |     2
4         | b      |     4
2         | c      |     3

db <>提琴here