对 SUM 销售的 SQL 查询,但只有给定 GROUP 的最新 SUM

Posted

技术标签:

【中文标题】对 SUM 销售的 SQL 查询,但只有给定 GROUP 的最新 SUM【英文标题】:SQL query to SUM sales but only SUM most recent on hand for a given GROUP 【发布时间】:2014-03-12 02:29:25 【问题描述】:

我在弄清楚如何以各种方式对表进行分组时遇到了一些问题,对已售出的单位数量进行求和,但仅对每个组中每个项目的最新现有单位进行求和。

这是一个示例数据集:http://www.sqlfiddle.com/#!2/3ff18/1

我需要能够以这样一种方式执行 GROUP BY,即 On Hand 列仅针对每个组中最近的项目求和。

我在使用 MAX(date) 的“自我加入”方面取得了一些进展,但在使用各种 GROUP BY 时我没有得到想要的结果。

在给定 sqlfiddle.com 数据集的情况下,我希望看到一些示例输出:

Category     Sold  On Hand
Electronics   500        0
Books         500        0
Other           0      100

Quarter  Category     Sold  On Hand
Q1       Electronics   400      100
Q1       Books         400      100
Q1       Other           0      100
Q2       Electronics   100        0
Q2       Books         100        0
Q2       Other           0      100

Month    Sold  On Hand 
January   300      800 
February  100      700 
March     200      500 
April     200      300 
May         0      300 <- This May entry isn't strickly necessary, but it would be nice
June      100      200 
July      100      100 <- This 100 units On Hand is from Item 987 that hasn't been sold

MAX(date) 方法让我感到困惑的一个领域是GROUP BY month。如果您查看上面的表格,您会注意到我希望在 7 月份看到 100 件在手……也就是说,除了 1 月份添加的第 987 件之外,所有单元都已售出,但有没卖。

几点说明:

这是使用 mysql,但如果 PostgreSQL 具有支持此功能的窗口函数,它会愿意尝试。 鉴于目前有 150 万条记录,该解决方案的性能非常重要。并且可能会增加数百万。

【问题讨论】:

【参考方案1】:

Postgres 中,您可以选择 a variety of window functions。

您有 DISTINCT ON 来选择每组列中 n 最大的行:Select first row in each GROUP BY group?

你有 date / time algebra 和 formatting 的函数(大部分你在 MySQL 中也有)。所以冗余存储月份和季度是没有意义的。只会让你的桌子膨胀并减慢你的速度。我相应地调整了您的表格布局。请参阅下面的小提琴。

使用这个相应简化的 Postgres 表:

CREATE TABLE tbl (
   item int
  ,on_hand int
  ,sold int
  ,thedate date
  ,category text
);

演示EXTRACT() & to_char():

SELECT EXTRACT(quarter FROM thedate)::int AS quarter_int
     , EXTRACT(month   FROM thedate)::int AS month_int
     , to_char(thedate, '"Q"Q')  AS quarter_text
     , to_char(thedate, 'Month') AS month_text
FROM   tbl
LIMIT 1;

仅获取每个(项目、月份)的最新行:

SELECT DISTINCT ON (item, date_trunc('month', thedate))
       *
FROM   tbl
ORDER  BY item, date_trunc('month', thedate), thedate DESC;

每个类别的总数:

SELECT category, sum(sold) AS sold, min(on_hand) AS on_hand
FROM  (
   SELECT category, sold
        , first_value(on_hand) OVER (PARTITION BY item
                                     ORDER BY thedate DESC) AS on_hand
   FROM tbl
   ) sub
GROUP  BY 1
ORDER  BY 1;

类别和月份相同:

SELECT category, to_char(month, 'YYYY-Mon') AS month
     , sum(sold) AS sold, min(on_hand) AS on_hand
FROM  (
   SELECT category, date_trunc('month', thedate) AS month, sold
        , first_value(on_hand) OVER (PARTITION BY item, date_trunc('month', thedate)
                                     ORDER BY thedate DESC) AS on_hand
   FROM tbl
   ) sub
GROUP  BY 1, sub.month
ORDER  BY 1, sub.month;

SQL Fiddle demo.

【讨论】:

以上是关于对 SUM 销售的 SQL 查询,但只有给定 GROUP 的最新 SUM的主要内容,如果未能解决你的问题,请参考以下文章

sql在查询之间不显示空值

需要一个 SQL 查询来从 SQL Server 数据库中获取特定条件下给定时间段的数据

SQl销售交易

制定 sql 查询时遇到问题

sql语句:将两个查询结果关联显示

销售统计饼状图