Postgresql中的日期限制运行平均值 - 如何划分为四个星期

Posted

技术标签:

【中文标题】Postgresql中的日期限制运行平均值 - 如何划分为四个星期【英文标题】:Date-bound running average in Postgresql - how to partition into four weeks 【发布时间】:2019-08-20 15:37:10 【问题描述】:

我有一张表,其中包含 sales_date(每周:每周六)、item_ID 和 sales。我想要一个四个星期的运行平均值。我需要将我的数据划分为每个 ID 为期 4 周的部分,但我不知道如何执行语法。

示例表:

ID  date    value   four_wk_average
<p>123  04/05/2019  1640.88 1640.88
<p>123  11/05/2019  2093.4  1867.14
<p>123  18/05/2019  2671.57 2135.28
<p>123  25/05/2019  2034.6  2110.11
<p>123  01/06/2019  1564.62 2001.01
<p>123  08/06/2019  2143.29 2024.73
<p>123  15/06/2019  2007    2022.19
<p>123  22/06/2019  2329.35 2060.59
<p>123  29/06/2019  2794.32 2142.11
<p>123  06/07/2019  3380.05 2265.91

当我运行下面的代码时,我得到了最右边的列 - 这是一个运行平均值,但它需要所有行,而不仅仅是我想要的当前行和前三行。

select
id,
date,
value,
avg(value) over (partition by id, (x.date between x.date and x.date - '22 days'::interval) order by date)

from
(select id, date::date, value from sales where date >= '2019-05-01') x

正确的值是

ID  date    value   four_wk_average
<p>123  04/05/2019  1640.88 1640.88
<p>123  11/05/2019  2093.4  1867.14
<p>123  18/05/2019  2671.57 2135.28
<p>123  25/05/2019  2034.6  2110.11
<p>123  01/06/2019  1564.62 2091.05
<p>123  08/06/2019  2143.29 2103.52
<p>123  15/06/2019  2007    1937.38
<p>123  22/06/2019  2329.35 2011.07
<p>123  29/06/2019  2794.32 2318.49
<p>123  06/07/2019  3380.05 2627.68

我认为我的分区将我的间隔部分作为布尔测试并返回 TRUE - 我不知道如何在窗口函数中表示日期范围。

谢谢!

【问题讨论】:

【参考方案1】:

demo:db<>fiddle

方式 1:这适用于 Postgres 11+ 和每周几条记录

SELECT
    *,
    AVG(value) OVER (ORDER BY the_date RANGE BETWEEN interval '4 weeks - 1 day' PRECEDING AND CURRENT ROW)
FROM
    sales

间隔为 4 周:4 周减去 1 天加上当天。


方式 2:这也适用于 Postgres 并且仅当确实每周只有一条记录

SELECT
    *,
    AVG(value) OVER (ORDER BY the_date ROWS BETWEEN 3 PRECEDING AND CURRENT ROW)
FROM
    sales

Further reading 关于窗口函数和ROWSRANGE 子句


方式 3:这是 Postgres 版本 和 每周几条记录的方式:

SELECT 
    s1.*,
    (SELECT AVG(s2.value)
     FROM sales s2
     WHERE s2.the_date <= s1.the_date
          AND s2.the_date > s1.the_date - interval '4 weeks')
FROM sales s1;

【讨论】:

Lifesaver:我使用了方式 2,效果很好。也感谢您的进一步阅读 - 我试图在互联网上搜索如何做到这一点,但我找不到任何东西。再次感谢。 嗨!我很抱歉没有早点回答。当我将所有数据放在一起时,这不起作用 - 在这种情况下,数据按国家和 ID 分组。您的三个选项中哪一个最适合这种情况?以 Excel 的方式思考,我想做一个 AVERAGEIFS,条件是 ID 和国家/地区匹配。或者我可以对我正在执行此操作的子查询进行任何排序,以使 PRECEDING ROW 语法起作用?谢谢! 不过,我当然可以尝试帮助您。但在那种情况下,我也确实需要样本数据和预期输出。所以请尝试创建一个小提琴(就像我在回答中所做的那样)和/或打开一个全新的问题!

以上是关于Postgresql中的日期限制运行平均值 - 如何划分为四个星期的主要内容,如果未能解决你的问题,请参考以下文章

计算PostgreSQL中的转发日期

(运行的干净代码)根据来自另一个数据帧的日期间隔和字符串条件获取一个数据帧中的值的平均值

PostgreSQL 中基于时间戳的移动平均线

来自每月日期范围数据的年平均值

PostgreSQL 中的 PERCENTILE_DISC() 作为窗口函数

如何用 postgresql 计算排列?