Postgres:使用 window 的平均每月收入总和

Postgres: Average of monthly revenue sums using window

我有 table 条 product/date 条交易记录,我想生成 table 月平均产品类别收入的摘要。结果将如下所示:

┌───────────────────┬────────────────────────┐
│ product_category  │ avg_monthly_revenue    │
├───────────────────┼────────────────────────┤
│ 5000              │       65003.04         │
│ 5100              │        3301.95         │
│ 5200              │       99029.00         │
...

我正在寻找类别总计的平均值,而我天真的尝试是返回每月交易收入的平均值。

我想要的是类别月度总计,然后是那些月的平均值。

我可以使用 sum() 和 avg() 函数的子查询聚合来做到这一点,但是我认为这可以通过使用 Postgres SQL Window Functions 的干净的小 select 来完成。奇怪的是,广泛的谷歌搜索没有产生适用的 SO 解决方案,所以我发布了一个问题。

数据的组织方式如下:

=#> \dt+ customer_transactions
        Table "customer_transactions"
┌─────────────────┬────────────────┬───────────┐
│       Column    │      Type      │ Modifiers │
├─────────────────┼────────────────┼───────────┤
│ order_day       │ date           │ not null  │
│ product_id      │ text           │ not null  │
│ product_category│ text           │ not null  │
│ customer_id     │ bigint         │ not null  │
│ revenue         │ numeric(38,14) │           │
│ units           │ integer        │           │
└─────────────────┴────────────────┴───────────┘

=#> select * from customer_transactions limit 2;
order_day   product_id   product_category   customer_id revenue
24-MAR-16   A000BC2351   5000               44502       5.85
02-NOV-16   A000CB0182   5200               99833       99.50
...

这是我使用 window 函数的幼稚尝试:

/* this doesn't work right, it generates the monthly transaction average*/
select      distinct product_category
            , avg(revenue) over (partition by date_trunc('month', order_day), product_category)  avg_cat_month_revenue

from        customer_transactions

# result accurate but not desired monthly item-cust-category-trxn average:
┌──────────────────┬─────────────────────────┐
│ product_category │   avg_cat_month_revenue │
├──────────────────┼─────────────────────────┤
│ 5000             │       12.0143           │
│ 5000             │       12.4989           │
...
│ 5100             │       13.5472           │
│ 5100             │       13.5643           │
...

借助 postgres 文档中有关 window 函数的帮助,我凭直觉得出了解决方案,这些组将应用于内部聚合函数,并且 window 用于其结果:

Window functions are permitted only in the SELECT list and the ORDER BY clause of the query. They are forbidden elsewhere, such as in GROUP BY, HAVING and WHERE clauses. This is because they logically execute after the processing of those clauses. Also, window functions execute after regular aggregate functions. This means it is valid to include an aggregate function call in the arguments of a window function, but not vice versa.

select      distinct product_category
            , avg(sum(revenue)) over (partition by product_category)  avg_rev

from        customer_transactions

group by    date_trunc('month', order_day), product_category

巧妙的部分是仅在 product_category 上进行分区,而不是 select 所有组(仅类别)并且知道这些组将仅应用于总和而不是平均值。

与 excel 中的手动旋转和平均相比,结果得到验证。

注意事项:

  • 使用nullif(revenue,0):当月总和为0时,平均值用较高的分母表示。如果您的 table 交易收入为零,请在您的被加数中使用 nullif。
  • 例如,您不能只添加另一个 avg accross grain 来按月获取类别之间的平均值,因为 select 围绕类别分组。