簡體   English   中英

PostgreSQL分組滾動平均值

[英]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;

任何幫助將非常感激。

我的回答是假設

  1. loggedtimestamp with time zonetimestamp with time zone ,這是記錄的唯一合理數據類型。

  2. 您的復雜日期算術假設計算時區UTC logged的值(否則為什么要使用'epoch'::timestamp作為基數?),舍入到下一個較低的小時。

  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)

鏈接的答案幾乎包含您需要的一切。 如果你想進一步“分組”(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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM