postgresql - Postgresql如何获取一个月内不同产品总金额的最大金额?

标签 postgresql sum max row-number case-when

我最近才开始使用 Postgresql。我有一个名为“sales”的表。

create table sales
    (
        cust    varchar(20),
        prod    varchar(20),
        day integer,
        month   integer,
        year    integer,
        state   char(2),
        quant   integer
    )

insert into sales values ('Bloom', 'Pepsi', 2, 12, 2001, 'NY', 4232);
insert into sales values ('Knuth', 'Bread', 23, 5, 2005, 'PA', 4167);
insert into sales values ('Emily', 'Pepsi', 22, 1, 2006, 'CT', 4404);
insert into sales values ('Emily', 'Fruits', 11, 1, 2000, 'NJ', 4369);
insert into sales values ('Helen', 'Milk', 7, 11, 2006, 'CT', 210);
...

总共有 500 行,10 个不同的产品和 5 个不同的客户。

看起来像这样: enter image description here

现在我需要找到最“受欢迎”和最“不受欢迎”的产品(总销量最多和最少的产品)以及 12 个月中每个月的相应总销量(即 SUM)(< strong>不分年份)。

结果应该是这样的:

enter image description here

现在我只能这样写查询了:

select month,
       prod,
       sum(quant)
from sales
group by month,prod
order by month,prod;

它给了我这样的结果:

enter image description here

现在我需要获取每个月的最大值。例如第1个月的前10个和中的最大值,依此类推...

我还需要获得总和的最小值(不管年份)。并且水平组合它们...我对此一无所知...

最佳答案

注意:对于 TLDR,请跳至末尾。

您的问题是一个非常有趣的教科书案例,因为它涉及 Postgres 的多个方面。

我经常发现将问题分解为多个子问题,然后将它们连接在一起以获得最终结果集非常有帮助。

在您的例子中,我看到了两个子问题:找到每个月最受欢迎的产品,以及找到每个月最不受欢迎的产品。

让我们从最受欢迎的产品开始:

WITH months AS (
  SELECT generate_series AS month
  FROM generate_series(1, 12)
)
SELECT DISTINCT ON (month)
  month,
  prod,
  SUM(quant)
FROM months
LEFT JOIN sales USING (month)
GROUP BY month, prod
ORDER BY month, sum DESC;

解释:

  • WITH 是一个 common table expression , 它充当临时表(在查询期间)和 有助于澄清查询。如果你觉得它令人困惑,你也可以选择 用于子查询。
  • generate_series(1, 12) 是一个 Postgres function它生成一系列整数,在本例中为 1 到 12。
  • LEFT JOIN 允许我们将每个销售关联到相应的月份。如果找不到给定月份的销售,则返回包含月份的行和具有 NULL 值的连接列。可以找到有关连接的更多信息 here .在您的情况下,使用 LEFT JOIN 很重要,因为使用 INNER JOIN 会排除从未销售过的产品(在这种情况下应该是最不受欢迎的产品)。
  • GROUP BY 用于对数量求和。
  • 在此阶段,您应该 - 可能 - 在任何给定月份拥有多种产品。我们只想保留每个月数量最多的那些。 DISTINCT ON 对此特别有用。给定一列,它允许我们保留每个值的第一次迭代。因此,首先按总和ORDER 销售额很重要,因为只会选择第一个。我们首先需要较大的数字,因此应使用 DESC(降序)。

我们现在可以对最不受欢迎的产品重复该过程:

WITH months AS (
  SELECT generate_series AS month
  FROM generate_series(1, 12)
)
SELECT DISTINCT ON (month)
  month,
  prod,
  SUM(quant)
FROM months
LEFT JOIN sales USING (month)
GROUP BY month, prod
ORDER BY month, sum;

结论(和 TLDR):

现在我们需要将两个查询合并为一个最终查询。

WITH months AS (
  SELECT generate_series AS month
  FROM generate_series(1, 12)
), agg_sales AS (
  SELECT
    month,
    prod,
    SUM(quant)
  FROM months
  LEFT JOIN sales USING (month)
  GROUP BY month, prod
), most_popular AS (
  SELECT DISTINCT ON (month)
    month,
    prod,
    sum
  FROM agg_sales
  ORDER BY month, sum DESC
), least_popular AS (
  SELECT DISTINCT ON (month)
    month,
    prod,
    sum
  FROM agg_sales
  ORDER BY month, sum
)
SELECT
  most_popular.month,
  most_popular.prod AS most_popular_prod,
  most_popular.sum AS most_pop_total_q,
  least_popular.prod AS least_popular_prod,
  least_popular.sum AS least_pop_total_q
FROM most_popular
  JOIN least_popular USING (month);

请注意,我使用了一个中间 agg_sales CTE 来尝试使查询更清晰一些并避免重复相同的操作两次,尽管这对 Postgres 的优化器来说应该不是问题。

希望您对我的回答满意。否则请不要犹豫发表评论!

编辑:虽然这个解决方案应该按原样工作,但我建议将您的日期存储为 TIMESTAMPTZ 类型的单个列。使用该类型操作日期通常要容易得多,如果您需要进一步分析和审计数据库,这始终是一种很好的做法。

只需使用 EXTRACT(MONTH FROM date) 即可获取任何日期的月份。

关于postgresql - Postgresql如何获取一个月内不同产品总金额的最大金额?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58291694/

相关文章:

postgresql - 当REVOKE GRANT被称为PostgreSQL时,二级权限会发生什么?

arrays - 如何在 pl/pgsql 中获取 foreach 中的当前键?

php - 为什么计算 1/(n * log(n) - n) 会破坏计算机?

c++ - C++ 中的 DBL_MAX 是什么?

java - 需要帮助确定最大和最小用户输入

django - 使用 Django 和 postgresql 创建 Azure 网站

java - Intellij 13 EclipseLink 类 [] 未找到错误

Java 求和 2 个负数

python 的 sum() 和非整数值

java - 如何显示列表中的最小值和最大值?