【问题标题】:Explode (duplicate) records based on timestamp range (PostgreSQL)根据时间戳范围展开(重复)记录(PostgreSQL)
【发布时间】:2021-12-01 12:18:51
【问题描述】:

我正在尝试将时间序列记录集转换为更适合数据分析的内容。考虑以下连续记录集(From、To、Value)

"2019-10-03 03:58:21+00"    "2019-10-03 03:59:04+00"    10
"2019-10-03 03:59:04+00"    "2019-10-03 03:59:54+00"    15
"2019-10-03 03:59:54+00"    "2019-10-03 04:02:00+00"    20
"2019-10-03 04:02:00+00"    "2019-10-03 04:02:10+00"    25

我希望在每分钟开始时有一条记录,代价是“重复”行。

"2019-10-03 03:58:21+00"    "2019-10-03 03:59:00+00"    10
"2019-10-03 03:59:00+00"    "2019-10-03 03:59:04+00"    10
"2019-10-03 03:59:04+00"    "2019-10-03 03:59:54+00"    15
"2019-10-03 03:59:54+00"    "2019-10-03 04:00:00+00"    20
"2019-10-03 04:00:00+00"    "2019-10-03 04:01:00+00"    20
"2019-10-03 04:01:00+00"    "2019-10-03 04:02:00+00"    20
"2019-10-03 04:02:00+00"    "2019-10-03 04:02:10+00"    25

第一行重复一次,因为它重叠了一分钟。第二个没有重复,因为它在一分钟内。第三个重复了两次,因为它重叠了 3 分钟。最后没有爆炸,因为它在一分钟内(但它也在一分钟内开始)。该值本身在展开的行中保持不变。

我觉得我的解决方案是 Window 函数 (lead/lag?)、generate_series() 和各种 date_part / date_trunc 调用的组合。可能是crosslateral 自加入...

目前使用的是 PostgreSQL 13.4,所以我应该可以访问最新最好的 API。如果有任何帮助,我也在使用 timescaledb 2.4.2 和超表,尽管它们的 time_bucket 函数似乎更多的是减少行数,而不是增加行数。

希望朝着正确的方向前进!

【问题讨论】:

  • 你检查过time_bucket_gapfill吗?可能这就是你要找的。​​span>
  • 多么棒的领导,非常感谢。但是,它只能与聚合一起使用。但现在我至少可以用传统的 postgresql 功能搜索“填补空白”了。

标签: postgresql time-series window-functions timescaledb


【解决方案1】:

正如我所料,它是 generate_series 和窗口函数的组合。但我没想到必须创建自己的locf 函数,我认为LEAD/LAG 可以选择记住最后一个已知/非空值。

以下代码采用一些已知记录,并将它们与生成的一系列时间戳合并。

我需要使用DISTINCT ON 来清除已生成的已知等价记录。

然后我终于可以使用LEAD 作为“下一个日期”,使用locf_any 作为结转值。

--https://www.joyofdata.de/blog/locf-linear-imputation-postgresql-tutorial/

DROP FUNCTION locf_s(ANYELEMENT, ANYELEMENT) CASCADE;
CREATE OR REPLACE FUNCTION locf_s(a ANYELEMENT, b ANYELEMENT)
RETURNS ANYELEMENT
LANGUAGE sql
AS '
  SELECT COALESCE(b, a)
';

DROP AGGREGATE IF EXISTS locf_any(ANYELEMENT);
CREATE AGGREGATE locf_any(ANYELEMENT) (
  SFUNC = locf_s,
  STYPE = ANYELEMENT
);

SELECT from_time, LEAD(from_time) OVER W, locf_any(reading) OVER W
FROM
(
  SELECT DISTINCT ON (from_time) from_time, reading FROM
  (
    WITH readings (from_time, reading) AS (VALUES
     ('2019-10-03 03:58:21+00', 10),
     ('2019-10-03 03:59:04+00', 15),
     ('2019-10-03 03:59:54+00', 20),
     ('2019-10-03 04:02:00+00', 25)
    )
    (
      SELECT from_time::TIMESTAMPTZ, reading::INTEGER FROM readings
      UNION ALL
      SELECT generate_series('2019-10-03 03:59:00+00', '2019-10-03 04:04:00+00', '1 minute'::INTERVAL)::TIMESTAMPTZ, NULL
    )
  ) X
  ORDER BY from_time, reading NULLS LAST
) Y
WINDOW W AS (ORDER BY from_time ASC);

【讨论】:

  • 你好杰夫,感谢分享!我认为如果您在 github.com/timescale/timescaledb-toolkit 项目上打开一个问题以改进 API 或添加一些选项来记住最后一个已知/非空值,那将是很棒的。
猜你喜欢
  • 2019-08-26
  • 1970-01-01
  • 1970-01-01
  • 2013-01-10
  • 1970-01-01
  • 1970-01-01
  • 2020-05-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多