[英]PostgreSQL Grouped Rolling Averages
我正在嘗試按項目ID列分組的設定時間段生成滾動平均值。
這是表格的基本布局和一些虛擬數據,剝離了絨毛:
----------------------------------------------------
| 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 |
----------------------------------------------------
我找到了關於滾動平均值的上一個問題的答案,但我似乎無法弄清楚如何按項目ID對平均值進行分組; 幾乎所有我走過的路都最終導致統計數字出錯。
這是我的出發點 - 我感覺我對ROW_NUMBER()OVER缺乏了解並沒有幫助。
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;
任何幫助將非常感激。
我的回答是假設
logged
是timestamp with time zone
的timestamp with time zone
,這是記錄的唯一合理數據類型。
您的復雜日期算術假設計算時區UTC logged
的值(否則為什么要使用'epoch'::timestamp
作為基數?),舍入到下一個較低的小時。
您希望按舍入的時間戳和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)
鏈接的答案幾乎包含您需要的一切。 如果你想進一步“分組”(f.ex. by itemid
),你只需要將這些“組”添加到窗口函數的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已經注意到)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.