【问题标题】:Finding products that were ordered 20% more times than the average of all other products in postgresql在 postgresql 中查找比所有其他产品的平均订购次数多 20% 的产品
【发布时间】:2021-12-24 04:36:26
【问题描述】:

我问了一个类似的问题,并得到了一些非常好的人的帮助。 How to find the average of all other products in postgresql。 这个问题不是全部,但我认为如果最难的部分可以解决,我可以自己解决剩下的问题,但显然我高估了自己的能力。所以我要发布另一个问题... :)

问题如下。

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

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

另一个表 Sales 如下所示:

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

我试图找出比所有其他同类产品的平均订购量高 20% 的产品

一种产品可以多次订购,每次订购的数量(数量)可能不同。如示例表中的ref02。我只包括了一个示例(ref02),但所有产品都是如此。因此,要查找特定产品的订购次数意味着从该产品的所有订单中找到订购数量的总和

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

+-----------+-----------+----------+
|ProductCode|    qty    |   ....   |
+-----------+-----------+----------+
|   ref02   |     16    |   ....   |
|   ref06   |     20    |   ....   |
|   ref07   |     11    |   ....   |
|   ref10   |     19    |   ....   |
|   .....   |   .....   |   ....   |
+-----------+-----------+----------+

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

Since product ref02 is 'ALBUMS' and there are two orders of ref02, the total orders will be 12+4=16. And ref07 and ref09 are also 'ALBUMS'. 
      So their average is (11+9)/2=10 < 12+4=16.

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+4)/3=8.3 <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.

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

我知道如何通过我从上一个问题How to find the average of all other products in postgresql 中获得的帮助找到所需的产品,但那时每种产品只有一个订单。如果每个产品有多个订单,我不知道如何进行。这是我在开头提到的“高估”位...... :(

我在上一个问题中收到的答案有这个问题: DEMO (db<>fiddle)。演示中的表格与我正在使用的表格更加相似,并且如您所见,一种产品有很多行。 (重复的行是偶然的。值恰好相同)

我正在使用 PostgreSQL,但该练习禁止使用多个关键字,包括:WITHOVERLIMITPARTITIONLATERAL。我意识到它们通常用于我找到的大多数解决方案以及提供给我的解决方案中,但我不能使用它们,因为否则不会返回任何结果...... :(

我知道不允许使用这些关键字会很烦人,但老实说我不知道​​该怎么做,所以请帮忙! :)

【问题讨论】:

    标签: sql postgresql


    【解决方案1】:

    我为所有组合编写了一个查询,按产品代码总计、按产品类型总计等。如果需要,您可以使用(SUM 值/计数值)计算平均值。

    select 
        main1.product_code, 
        main1.product_type, 
        main1.total as "Total by Product Code", 
        main1.sales_count as "Count by Product Code",
        main2.total as "Total by Product Type", 
        main2.sales_count as "Count by Product Type",
        main2.total - main1.total as "Total by Other Products Types (ignore this Product Code)", 
        main2.sales_count - main1.sales_count as "Count by Other Products Types (ignore this Product Code)"
    from 
        (
            select 
                s.product_code, 
                p.product_type,  
                sum(s.qty) as total, 
                count(*) as sales_count
            from 
                examples.sales s
            left join 
                examples.products p on p.product_code = s.product_code 
            group by 
                s.product_code, p.product_type
        ) main1 
    left join 
        (
            select t1.product_type, sum(t1.qty) as total, count(*) as sales_count from (
                select * from examples.sales s  
                left join examples.products p on p.product_code = s.product_code 
            ) t1 
            group by t1.product_type
        ) main2 on main1.product_type = main2.product_type 
    

    结果:

    Pr.Code Pr.Type Total by Pr.Code Count by Pr.Code Total by Pr.Type Count by Pr.Type (ignore this Product Code) Total by Other Pr.Types Count by Other Pr.Types (ignore this Product Code)
    ref29 TOYS 5 1 27 3 22 2
    ref06 BOOKS 20 1 34 2 14 1
    ref13 TOYS 3 1 27 3 24 2
    ref02 ALBUMS 16 2 36 4 20 2
    ref10 TOYS 19 1 27 3 8 2
    ref07 ALBUMS 11 1 36 4 25 3
    ref04 BOOKS 14 1 34 2 20 1
    ref09 ALBUMS 9 1 36 4 27 3

    【讨论】:

      【解决方案2】:

      修复设置中的两个错误

      1.

      一个产品可以多次订购...

      它仍应在Products 表中出现一次ref02 的第二个条目是错误的。

      2.

      因此,要查找特定产品的订购次数意味着从该产品的所有订单中找到订购数量的总和

      所以你对ref07 的理由不成立:

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

      根据您的定义,分别计算 ref02 的两次销售额是错误的。对每个产品使用 sums

      Since product ref07 is 'ALBUMS', and ref02 and ref09 are also 'ALBUMS'.           
            So their average is (16+9)/2 = 12.5 > 11.  -- doesn't qualify!
      

      回答

      找出比所有其他同类产品的平均订购量多 20% 的产品。

      我首先提出了一个适当的解决方案:使用带有自定义窗口框架的窗口函数对 Postgres 11+ 进行有效查询 sum()

      SELECT product_code, orders
      FROM  (
         SELECT product_code, sum(s.orders) AS orders
              , avg(sum(s.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)
         GROUP  BY product_code, p.product_type
         ) sub
      WHERE  avg_orders * 1.2 < orders
      ORDER  BY product_code;  -- optional
      

      结果(已修复上述错误):

      product_code orders
      ref02 16
      ref06 20
      ref10 19

      比下面的效率高得多。
      Postgres 可以在同一查询级别的聚合上应用窗口函数。见:

      根据您的要求,一个低效的解决方案围绕现代 SQL 功能工作:

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

      db小提琴here

      同样的结果。

      我们必须在子查询中重复求和的基本聚合,因为我们不能使用 CTE 来实现它。 (可能的剩余解决方法:使用临时表而不是。)

      我对您上一个问题的回答中的基本内容:

      【讨论】:

        猜你喜欢
        • 2021-12-23
        • 2020-03-12
        • 1970-01-01
        • 2011-08-03
        • 1970-01-01
        • 1970-01-01
        • 2015-05-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多