2017-03-24 10 views
1

アイテムIDカラムでグループ化された設定期間にわたってローリング平均を生成しようとしています。 PostgreSQLグループ化ローリング平均

---------------------------------------------------- 
| id | itemid | isup | logged    | 
---------------------------------------------------- 
| 1 | 1  | true | 2017-03-23 12:55:00 | 
| 2 | 1  | false | 2017-03-23 12:57:00 | 
| 3 | 1  | true | 2017-03-23 13:07:00 | 
| 4 | 1  | false | 2017-03-23 13:09:00 | 
| 5 | 1  | true | 2017-03-23 13:50:00 | 
| 6 | 2  | false | 2017-03-23 12:55:00 | 
| 7 | 2  | true | 2017-03-23 14:00:00 | 
| 8 | 2  | false | 2017-03-23 14:03:00 | 
---------------------------------------------------- 

私は answer to a previous question on rolling averagesを見つけたが、私はかなりによってどのようにグループの平均値を見つけ出すように見えることはできません。綿毛が取り除かで

はここで、テーブルといくつかのダミーデータの基本的なレイアウトですアイテムID。ほとんど私がダウンした道は統計が間違っていて終わってしまった。

ここに私の出発点があります。私はROW_NUMBER()の理解が不足していても問題を解決できないと感じています。

SELECT id, itemid, AVG(isup) 
    OVER (PARTITION BY groupnr ORDER BY logged) AS averagehour 
FROM (  
    SELECT id, itemid, isup, logged, intervalgroup, 
     itemid - ROW_NUMBER() OVER (
      partition by intervalgroup ORDER BY logged) AS groupnr 
    FROM (
     SELECT id, itemid, logged, 
      CASE WHEN isup = TRUE THEN 1 ELSE 0 END AS isup, 
      'epoch'::TIMESTAMP + '3600 seconds'::INTERVAL * 
       (EXTRACT(EPOCH FROM logged)::INT4/3600) AS intervalgroup 
     FROM uplog 
) alias_inner 
) alias_outer 
ORDER BY logged; 

ご協力いただければ幸いです。

+4

"グループ化されたローリング平均"は非常に一般的です。あなたがしようとしていることを説明してください。サンプルデータと望ましい結果が得られます。 –

答えて

0

リンク答えはあなたが必要とするほとんどすべてが含まれています。あなたは、「グループ」、さらに(itemidによってf.ex.)したい場合は、あなただけのウィンドウ関数のPARTITION BY条項にそれらの「グループ」を追加する必要があります:

select *, avg(isup::int) over (partition by itemid, group_nr order by logged) as rolling_avg 
from  (
    select *, id - row_number() over (partition by itemid, interval_group order by logged) as group_nr 
    from (
     select *, 'epoch'::timestamp + '3600 seconds'::interval * (extract(epoch from logged)::int4/3600) as interval_group 
     from dummy 
    ) t1 
) t2 
order by itemid, logged 

をしかし、このidのギャップが&ではないため、テーブルのタイムスタンプフィールドで順番に処理されます(リンクされた回答)。それはそうではないなら、あなたは

row_number() over (partition by itemid order by logged) - row_number() over (partition by itemid, interval_group order by logged) as group_nr 

代わりのid - row_number() ...必要があります。あなただけの時間ごとにグループを使用しようとしている場合も

http://rextester.com/YBSC43615

、あなたが使用することができます。代わりに、より一般的な算術の

date_trunc('hour', logged) as interval_group 

を(@LaurenzAlbeはすでに気づいたように)。

+0

ああ、私はパーティションに複数のエントリを持つことができたとは思いませんでした! – GMemory

0

私の答えはloggedロギングのための唯一の合理的なデータ型であるtimestamp with time zone、あること

  1. を前提としています。あなたの複雑な日付の計算がタイムゾーンUTC(他の理由をベースとして'epoch'::timestampを使うのでしょうか?)でloggedの値を計算すると仮定されて

  2. 、次の低い時間に丸め。

  3. この丸められたタイムスタンプでグループ化する場合はitemidとしてください。ここで

の答えのようになります。

SELECT *, 
     avg(isup::integer) 
      OVER (PARTITION BY itemid, 
          date_trunc('hour', logged AT TIME ZONE 'UTC') 
       ) average, 
     date_trunc('hour', logged AT TIME ZONE 'UTC') avg_interval 
FROM uplog 
ORDER BY logged; 

┌────┬────────┬──────┬────────────────────────┬────────────────────────┬─────────────────────┐ 
│ id │ itemid │ isup │   logged   │  average   │ avg_interval  │ 
├────┼────────┼──────┼────────────────────────┼────────────────────────┼─────────────────────┤ 
│ 6 │  2 │ f │ 2017-03-23 12:55:00+01 │ 0.00000000000000000000 │ 2017-03-23 11:00:00 │ 
│ 1 │  1 │ t │ 2017-03-23 12:55:00+01 │ 0.50000000000000000000 │ 2017-03-23 11:00:00 │ 
│ 2 │  1 │ f │ 2017-03-23 12:57:00+01 │ 0.50000000000000000000 │ 2017-03-23 11:00:00 │ 
│ 3 │  1 │ t │ 2017-03-23 13:07:00+01 │ 0.66666666666666666667 │ 2017-03-23 12:00:00 │ 
│ 4 │  1 │ f │ 2017-03-23 13:09:00+01 │ 0.66666666666666666667 │ 2017-03-23 12:00:00 │ 
│ 5 │  1 │ t │ 2017-03-23 13:50:00+01 │ 0.66666666666666666667 │ 2017-03-23 12:00:00 │ 
│ 7 │  1 │ t │ 2017-03-23 14:00:00+01 │ 0.50000000000000000000 │ 2017-03-23 13:00:00 │ 
│ 8 │  1 │ f │ 2017-03-23 14:03:00+01 │ 0.50000000000000000000 │ 2017-03-23 13:00:00 │ 
└────┴────────┴──────┴────────────────────────┴────────────────────────┴─────────────────────┘ 
(8 rows) 
関連する問題