13

タイムスタンプと測定を含むテーブルを持つPostgreSQL9.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
...                  ...

1時間ごとに8時間の範囲で値を平均する必要があります。言い換えれば、私は1時間から8時間、2時間から9時間、3時間から10時間などの平均が必要です。

私はそのような質問をどのように進めるのか分かりません。私はいたるところを探しましたが、どの機能を探すべきかについての手がかりもありません。

私が見つけた終値は、時間/日平均またはブロック平均(たとえば、1時間から8時間、9時間から16時間など)です。しかし、これらの場合、タイムスタンプはdate_trunc()関数を使用して単純に変換されます(以下の例のように)。これは私には役に立ちません。

私が探しているのは、これに似た機能です

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

ただし、group-by句では、1時間ごとにある種の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を加えたものです。これは、1時間ごとに1つの行があることを前提としています。あなたのサンプルデータはそれを暗示しているようですが、あなたは指定しませんでした。

このように、セット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 に答える