【问题标题】:How to find the average of all other products in postgresql如何在postgresql中找到所有其他产品的平均值
【发布时间】:2021-12-23 13:42:40
【问题描述】:

我有一张表Products,如下所示:

+-----------+-----------+----------+
|ProductCode|ProductType|   ....   |
+-----------+-----------+----------+
|   ref01   |   BOOKS   |   ....   |
|   ref02   |   ALBUMS  |   ....   |
|   ref06   |   BOOKS   |   ....   |
|   ref04   |   BOOKS   |   ....   |
|   ref07   |   ALBUMS  |   ....   |
|   ref10   |   TOYS    |   ....   |
|   ref13   |   TOYS    |   ....   |
|   ref09   |   ALBUMS  |   ....   |
|   ref29   |   TOYS    |   ....   |
|   .....   |   .....   |   ....   |
+-----------+-----------+----------+

另一个表Sales,如下所示:

+-----------+-----------+----------+
|ProductCode|   Orders  |   ....   |
+-----------+-----------+----------+
|   ref01   |     15    |   ....   |
|   ref02   |     12    |   ....   |
|   ref06   |     20    |   ....   |
|   ref04   |     14    |   ....   |
|   ref07   |     11    |   ....   |
|   ref10   |     19    |   ....   |
|   ref13   |      3    |   ....   |
|   ref09   |      9    |   ....   |
|   ref29   |      5    |   ....   |
|   .....   |   .....   |   ....   |
+-----------+-----------+----------+

我正在尝试查找订购量超过所有其他同类产品的平均值的产品。

通过手动计算,结果会是这样的:

+-----------+-----------+----------+
|ProductCode|   Orders  |   ....   |
+-----------+-----------+----------+
|   ref02   |     12    |   ....   |
|   ref06   |     20    |   ....   |
|   ref07   |     11    |   ....   |
|   ref10   |     19    |   ....   |
|   .....   |   .....   |   ....   |
+-----------+-----------+----------+

因此,如果查看类型 ALBUMS 和产品 ref02,那么我需要找到所有其他 ALBUMS 的订单的平均值。 在这种情况下,它是ref06ref04 的平均值,但实际表中还有更多。所以我需要做的是:

Since product ref02 is 'ALBUMS', and ref07 and ref09 are also 'ALBUMS'. 
      So their average is (11+9)/2=10 <12.

Since product ref06 is 'BOOKS', and **ref01** and ref04 are also 'BOOKS'.                     
      So their average is (15+14)/2=14.5 <20.

Since product ref07 is 'ALBUMS', and **ref02** and ref09 are also 'ALBUMS'.           
      So their average is (12+9)/2=10.5<11.

Since product ref10 is 'TOYS', and ref13 and ref29 are also 'TOYS'           
      So their average is (3+5)/2=4<19.

The rest does not satisfy the condition thus will not be in the result.

我知道如何并且能够找到同一类型下所有产品的订单平均值,但我不知道如何找到同一类型下所有其他产品的订单平均值。

我正在使用 PostgreSQL,但不能使用以下任何关键字:WITHOVERLIMITPARTITION

【问题讨论】:

  • 您为什么想要使用具有窗口功能的卓越解决方案?
  • 如果这是一个练习或家庭作业,那是一个非常愚蠢的禁止使用modern SQL
  • @ErwinBrandstetter 很抱歉给您带来麻烦,但这是一种练习,并不是我不想使用它们,而是我不被允许使用。
  • @a_horse_with_no_name 我不反对,但那是我正在合作的人...... :( 有什么想法吗?

标签: sql postgresql aggregate window-functions


【解决方案1】:

这是我将在 Postgres 11 或更高版本中使用的内容:
使用自定义框架定义的窗口函数的解决方案:

SELECT product_code, orders
FROM  (
   SELECT product_code, s.orders
        , avg(orders) OVER (PARTITION BY p.product_type
                            ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
                            EXCLUDE CURRENT ROW) AS avg_orders
   FROM   product p
   JOIN   sales s USING (product_code)
   ) sub
WHERE  orders > avg_orders 
ORDER  BY product_code;  -- optional

我希望它表现最好。
阅读the manual 了解窗口函数的详细信息。

这就是您要的:
没有 CTE、窗口函数或 LIMIT 的解决方案(适用于任何现代 Postgres 版本):

SELECT product_code, s.orders
FROM   product p
JOIN   sales s USING (product_code)
JOIN   LATERAL (
   SELECT avg(orders) AS avg_orders
   FROM   product p1
   JOIN   sales s1 USING (product_code)
   WHERE  p1.product_type =  p.product_type
   AND    p1.product_code <> p.product_code
   ) a ON a.avg_orders < s.orders
ORDER  BY product_code;  -- optional

两者都能产生你想要的结果。

db小提琴here

关于LATERAL

【讨论】:

  • 谢谢!有用!但是作为问题的补充,如果 ProductCode 出现多次并且必须使用其总和进行比较怎么办。在后一种解决方案中,这种修改会发生在哪里? :)
  • @Hayul:请提出一个新的问题。评论不是地方,你已经经常改变这个了。 (在给出答案后,根本不应该更改问题。)您可以随时链接到此问题以获取上下文。
  • 对不起,我会这么做的。只是我认为如果我知道如何处理最困难的部分,我可以解决剩下的问题。事实证明,我高估了我的能力...... :(
  • @HayulKim:那么 this 问题的回答是否正确? stackoverflow.com/help/someone-answers
【解决方案2】:

我们可以在这里尝试使用AVG()作为解析函数:

WITH cte AS (
    SELECT p.ProductCode, p.ProductType, s.Orders,
           AVG(s.Orders) OVER (PARTITION BY p.ProductType) AS AvgOrders
    FROM Products p
    INNER JOIN Sales s ON s.ProductCode = p.ProductCode
)

SELECT ProductCode, ProductType, Orders
FROM cte
WHERE Orders > AvgOrders;

Demo

【讨论】:

  • 首先,非常感谢您的帮助!这真的是我的错,但你的回答对我来说真的不起作用。我的意思是它工作正常,但有这个要求我不允许使用 WITH。我应该早点提到它,但我忘记了。我很抱歉。除非 WITH 不是关键部分?你介意再解释一下吗?我对此并没有真正的经验。 :)
  • 然后内联 CTE。将底部查询中的FROM cte 替换为FROM (SELECT p.ProductCode, p.ProductType, ... ) t ...检查the updated demo here
  • 感谢您的更新!但我担心这也不起作用,因为 OVER 和 PARTITION 也是不允许的...... :(
  • 很抱歉给您带来了麻烦,但是...还有其他的方法吗?
  • @HayulKim 抱歉,我已经回答了您的问题两次,并为这两个版本提供了工作演示。恐怕我目前无法提供更多帮助。
猜你喜欢
  • 2021-12-24
  • 2020-03-12
  • 2021-11-18
  • 2019-06-11
  • 1970-01-01
  • 2017-07-07
  • 2021-06-04
  • 1970-01-01
  • 2019-01-08
相关资源
最近更新 更多