如何获得一个月内在Postgresql中不同产品的最大总金额?

问题描述 投票:1回答:1

我最近才刚开始使用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)。不论年份)。

结果应该是这样的:

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个总和中的最大值,依此类推...

我还需要获得总和的最小值(

不管年份

)。还有水平组合 ...我对此一无所知...
postgresql sum max row-number case-when
1个回答
1
投票
注意:对于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;

说明:

    WITHcommon 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 ), last_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)即可获得任何日期的月份。

  • © www.soinside.com 2019 - 2024. All rights reserved.