【问题标题】:SQL query to SUM sales but only SUM most recent on hand for a given GROUP对 SUM 销售的 SQL 查询,但只有给定 GROUP 的最新 SUM
【发布时间】: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 万条记录,该解决方案的性能非常重要。并且可能会增加数百万。

【问题讨论】:

    标签: mysql sql postgresql date-arithmetic window-functions


    【解决方案1】:

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

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

    你有 date / time algebraformatting 的函数(大部分你在 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.

    【讨论】:

      猜你喜欢
      • 2018-05-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多