对 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的主要内容,如果未能解决你的问题,请参考以下文章