13

我有一个 PostgreSQL 9.1 数据库,其中包含一个包含时间戳和测量值的表

'2012-10-25 01:00'   2
'2012-10-25 02:00'   5
'2012-10-25 03:00'   12
'2012-10-25 04:00'   7
'2012-10-25 05:00'   1
...                  ...

我需要在每小时 8 小时的范围内平均该值。换句话说,我需要 1h-8h、2h-9h、3h-10h 等的平均值。

我不知道如何进行这样的查询。我到处寻找,但也不知道要寻找什么功能。

我发现的收盘价是每小时/每天的平均值或块平均值(例如 1h-8h、9h-16h 等)。但在这些情况下,时间戳只是使用date_trunc()函数进行转换(如下例所示),这对我没有用处。

我想我正在寻找的是与此类似的功能

SELECT    date_trunc('day', timestamp), max(value) 
FROM      table_name
GROUP BY  date_trunc('day', timestamp);

但是随后在 group-by 子句中使用某种 8 小时范围来表示每个小时。这甚至可能吗?

4

2 回答 2

8

带有自定义框架的窗口函数使这变得非常简单

SELECT ts
      ,avg(val) OVER (ORDER BY ts
                      ROWS BETWEEN CURRENT ROW AND 7 FOLLOWING) AS avg_8h
FROM tbl;

sqlfiddle 上的现场演示。

每个平均值的框架是当前行加上以下 7 行。这假设您每小时恰好有一行。您的样本数据似乎暗示了这一点,但您没有具体说明。

它的方式是,avg_8h对于集合的最后(根据ts)7 行,用更少的行计算,直到最后一行的值等于它自己的平均值。您没有指定如何处理特殊情况。

于 2012-11-18T00:31:22.470 回答
1

关键是创建一个虚拟表来加入您的结果集。该generate_series功能可以通过以下方式帮助做到这一点:

SELECT
    start
    , start + interval '8 hours' as end
FROM (
    SELECT generate_series(
        date'2012-01-01'
        , date'2012-02-02'
        , '1 hour'
    ) AS start
) x;

这会产生类似这样的输出:

         start          |          end           
------------------------+------------------------
 2012-01-01 00:00:00+00 | 2012-01-01 08:00:00+00
 2012-01-01 01:00:00+00 | 2012-01-01 09:00:00+00
 2012-01-01 02:00:00+00 | 2012-01-01 10:00:00+00
 2012-01-01 03:00:00+00 | 2012-01-01 11:00:00+00

这给了你一些东西来加入你的数据。这样,查询如下:

SELECT
    y.start
    , round(avg(ts_val.v))
FROM
    ts_val,
    (
        SELECT
            start
            , start + interval '8 hours' as end
        FROM (
            SELECT generate_series(
                date'2012-01-01'
                , date'2012-02-02'
                , '1 hour'
            ) AS start
        ) x
    ) y
WHERE
    ts BETWEEN y.start AND y.end
GROUP BY
    y.start
ORDER BY
    y.start
;

对于以下数据

         ts          | v 
---------------------+---
 2012-01-01 01:00:00 | 2
 2012-01-01 09:00:00 | 2
 2012-01-01 10:00:00 | 5
(3 rows)

会产生以下结果:

         start          | round 
------------------------+-------
 2012-01-01 00:00:00+00 |   2.0
 2012-01-01 01:00:00+00 |   2.0
 2012-01-01 02:00:00+00 |   3.5
 2012-01-01 03:00:00+00 |   3.5
 2012-01-01 04:00:00+00 |   3.5
 2012-01-01 05:00:00+00 |   3.5
 2012-01-01 06:00:00+00 |   3.5
 2012-01-01 07:00:00+00 |   3.5
 2012-01-01 08:00:00+00 |   3.5
 2012-01-01 09:00:00+00 |   3.5
 2012-01-01 10:00:00+00 |   5.0
(11 rows)
于 2012-11-15T23:34:11.000 回答