如何计算 SQL 总销售额的每日快照?
How can I calculate daily snapshots of my total sales on SQL?
我有一个 table(我们称它为 DiodeSales),它告诉我二极管销售总数,按日期、二极管颜色和国家/地区分组。这是此架构的示例:
Date Color Country Sales
June, 20 2016 00:00:00 Green US 1
June, 20 2016 00:00:00 Red Japan 1
June, 20 2016 00:00:00 Red US 1
June, 21 2016 00:00:00 Red US 1
June, 22 2016 00:00:00 Green US 1
June, 22 2016 00:00:00 Red US 1
June, 23 2016 00:00:00 Green US 1
June, 23 2016 00:00:00 Red Japan 1
June, 23 2016 00:00:00 Red US 1
June, 24 2016 00:00:00 Green US 1
June, 24 2016 00:00:00 Red US 1
我希望能够有一个额外的列,告诉我到那时为止我们已经售出多少个二极管。因此,例如,使用上述数据,{June 23, Red, 1, US} 行的总销售额将为 4,因为那时我们在美国售出了 4 个红色二极管。
我最初认为累积总和可以解决问题。所以我这样写:(sqlfiddle here)
SELECT
t1.Date,
t1.Color,
t1.Country,
t1.Sales,
SUM(t2.Sales) AS CumulativeSales
FROM DiodeSales AS t1
INNER JOIN DiodeSales AS t2
ON t1.Date >= t2.Date
AND t1.Color = t2.Color
AND t1.Country = t2.Country
GROUP BY
t1.Date,
t1.Color,
t1.Country
正如预期的那样,这给出了累计总和,但它没有给出给定日期在给定国家/地区的给定颜色的总销售额。特别是,由于某些特定日期在某些国家/地区的销售额可能为 0,因此它们不会具有与之关联的累积值。例如,考虑前面 table:
的结果
Date Color Country Sales CumulativeSales
June, 20 2016 00:00:00 Green US 1 1
June, 20 2016 00:00:00 Red Japan 1 1
June, 20 2016 00:00:00 Red US 1 1
June, 21 2016 00:00:00 Red US 1 2
June, 22 2016 00:00:00 Green US 1 2
June, 22 2016 00:00:00 Red US 1 3
June, 23 2016 00:00:00 Green US 1 3
June, 23 2016 00:00:00 Red Japan 1 2
June, 23 2016 00:00:00 Red US 1 4
June, 24 2016 00:00:00 Green US 1 4
June, 24 2016 00:00:00 Red US 1 5
如果我要查找 6 月 24 日与日本对应的列,我将一无所获(因为那天没有日本销售,所以那天没有日本行)。我认为在 SQL 中没有办法做到这一点,但是否可以在某些国家/地区没有销售的日子里用值填充此结果 table?起始 table 对于某些国家/地区,每天至少会有一列。
我知道我可以写一个简单的
SELECT SUM(Sales) FROM DiodeSales
WHERE Date <= @someDate AND Color = @someColor AND Country = @someCountry
获取此信息,但这是针对 table 的,必须以这种方式格式化才能被另一个已经制作的软件使用。
编辑:有人提到这是计算 Running Total in SQL Server 的潜在重复项,但 post 仅在计算 运行 总和时解决效率问题。我已经有多种方法来计算这个总和,但我正在寻找一种方法来解决在该国家/地区没有销售的日子里缺少 day/country 组合的问题。对于上面的示例,固定查询将 return this:
Date Color Country Sales CumulativeSales
June, 20 2016 00:00:00 Green US 1 1
June, 20 2016 00:00:00 Red Japan 1 1
June, 20 2016 00:00:00 Red US 1 1
June, 21 2016 00:00:00 Green US 0 1
June, 21 2016 00:00:00 Red Japan 0 1
June, 21 2016 00:00:00 Red US 1 2
June, 22 2016 00:00:00 Green US 1 2
June, 22 2016 00:00:00 Red Japan 0 1
June, 22 2016 00:00:00 Red US 1 3
June, 23 2016 00:00:00 Green US 1 3
June, 23 2016 00:00:00 Red Japan 1 2
June, 23 2016 00:00:00 Red US 1 4
June, 24 2016 00:00:00 Green US 1 4
June, 24 2016 00:00:00 Red Japan 0 2
June, 24 2016 00:00:00 Red US 1 5
试试这个:
SELECT [Date], Color, Country, Sales,
SUM(Sales) OVER(PARTITION BY Color, Country ORDER BY [Date] rows unbounded preceding) as RunningTotal
FROM YourTable
ORDER BY [Date], Color
它产生了预期的输出。
[编辑]
如果您正在寻找缺失日期、国家和颜色的解决方案,请试试这个(将 @tmp
替换为您的 table 的名称):
SELECT A.[Date], A.Color, A.Country, COALESCE(B.Sales, 0) AS Sales
, SUM(COALESCE(B.Sales, 0)) OVER(PARTITION BY A.Color, A.Country ORDER BY A.[Date] rows unbounded preceding) as RunningTotal
FROM (
SELECT [Date], Color, Country
FROM (SELECT DISTINCT [Date] FROM @tmp) AS q1 CROSS JOIN
(SELECT DISTINCT Color FROM @tmp) AS q2 CROSS JOIN
(SELECT DISTINCT Country FROM @tmp) AS q3
) AS A
LEFT JOIN @tmp AS B ON A.[Date] = B.[Date] AND A.Color= B.Color AND A.Country = B.Country
ORDER BY A.[Date], A.Color
以上查询产生:
Date Color Country Sales RunningTotal
2016-06-20 Green Japan 0 0
2016-06-20 Green US 1 1
2016-06-20 Red Japan 1 1
2016-06-20 Red US 1 1
2016-06-21 Green US 0 1
2016-06-21 Green Japan 0 0
2016-06-21 Red US 1 2
2016-06-21 Red Japan 0 1
2016-06-22 Green Japan 0 0
2016-06-22 Green US 1 2
2016-06-22 Red Japan 0 1
2016-06-22 Red US 1 3
2016-06-23 Green US 1 3
2016-06-23 Green Japan 0 0
2016-06-23 Red US 1 4
2016-06-23 Red Japan 1 2
2016-06-24 Green Japan 0 0
2016-06-24 Green US 1 4
2016-06-24 Red Japan 0 2
2016-06-24 Red US 1 5
我认为你应该使用左连接而不是内连接
SELECT
t.Date,
t.Color,
t.Country,
t.CumulativeSales
from DiodeSales t
left join
(SELECT
t1.Date,
t1.Color,
t1.Country,
t1.Sales,
SUM(t2.Sales) AS CumulativeSales
FROM DiodeSales AS t1
GROUP BY
t1.Date,
t1.Color,
t1.Country) t2
on
t.Date=t2.date
and t.Color=t2.color
and t.Country=t2.country
试试这个
Select distinct Date into SalesDate From DiodeSales
SELECT S.Date,t.Color,t.Country,t.CumulativeSales
from DiodeSales t left join
(SELECt t1.Date,t1.Color,t1.Country,t1.Sales,
SUM(t2.Sales) AS CumulativeSales FROM DiodeSales AS t1
GROUP BY
t1.Date,
t1.Color,
t1.Country) t2 on
S.Date=t2.date
and t.Color=t2.color
and t.Country=t2.country
join
SalesDate S
on t.date=S.date
我有一个 table(我们称它为 DiodeSales),它告诉我二极管销售总数,按日期、二极管颜色和国家/地区分组。这是此架构的示例:
Date Color Country Sales June, 20 2016 00:00:00 Green US 1 June, 20 2016 00:00:00 Red Japan 1 June, 20 2016 00:00:00 Red US 1 June, 21 2016 00:00:00 Red US 1 June, 22 2016 00:00:00 Green US 1 June, 22 2016 00:00:00 Red US 1 June, 23 2016 00:00:00 Green US 1 June, 23 2016 00:00:00 Red Japan 1 June, 23 2016 00:00:00 Red US 1 June, 24 2016 00:00:00 Green US 1 June, 24 2016 00:00:00 Red US 1
我希望能够有一个额外的列,告诉我到那时为止我们已经售出多少个二极管。因此,例如,使用上述数据,{June 23, Red, 1, US} 行的总销售额将为 4,因为那时我们在美国售出了 4 个红色二极管。
我最初认为累积总和可以解决问题。所以我这样写:(sqlfiddle here)
SELECT
t1.Date,
t1.Color,
t1.Country,
t1.Sales,
SUM(t2.Sales) AS CumulativeSales
FROM DiodeSales AS t1
INNER JOIN DiodeSales AS t2
ON t1.Date >= t2.Date
AND t1.Color = t2.Color
AND t1.Country = t2.Country
GROUP BY
t1.Date,
t1.Color,
t1.Country
正如预期的那样,这给出了累计总和,但它没有给出给定日期在给定国家/地区的给定颜色的总销售额。特别是,由于某些特定日期在某些国家/地区的销售额可能为 0,因此它们不会具有与之关联的累积值。例如,考虑前面 table:
的结果Date Color Country Sales CumulativeSales June, 20 2016 00:00:00 Green US 1 1 June, 20 2016 00:00:00 Red Japan 1 1 June, 20 2016 00:00:00 Red US 1 1 June, 21 2016 00:00:00 Red US 1 2 June, 22 2016 00:00:00 Green US 1 2 June, 22 2016 00:00:00 Red US 1 3 June, 23 2016 00:00:00 Green US 1 3 June, 23 2016 00:00:00 Red Japan 1 2 June, 23 2016 00:00:00 Red US 1 4 June, 24 2016 00:00:00 Green US 1 4 June, 24 2016 00:00:00 Red US 1 5
如果我要查找 6 月 24 日与日本对应的列,我将一无所获(因为那天没有日本销售,所以那天没有日本行)。我认为在 SQL 中没有办法做到这一点,但是否可以在某些国家/地区没有销售的日子里用值填充此结果 table?起始 table 对于某些国家/地区,每天至少会有一列。
我知道我可以写一个简单的
SELECT SUM(Sales) FROM DiodeSales WHERE Date <= @someDate AND Color = @someColor AND Country = @someCountry
获取此信息,但这是针对 table 的,必须以这种方式格式化才能被另一个已经制作的软件使用。
编辑:有人提到这是计算 Running Total in SQL Server 的潜在重复项,但 post 仅在计算 运行 总和时解决效率问题。我已经有多种方法来计算这个总和,但我正在寻找一种方法来解决在该国家/地区没有销售的日子里缺少 day/country 组合的问题。对于上面的示例,固定查询将 return this:
Date Color Country Sales CumulativeSales June, 20 2016 00:00:00 Green US 1 1 June, 20 2016 00:00:00 Red Japan 1 1 June, 20 2016 00:00:00 Red US 1 1 June, 21 2016 00:00:00 Green US 0 1 June, 21 2016 00:00:00 Red Japan 0 1 June, 21 2016 00:00:00 Red US 1 2 June, 22 2016 00:00:00 Green US 1 2 June, 22 2016 00:00:00 Red Japan 0 1 June, 22 2016 00:00:00 Red US 1 3 June, 23 2016 00:00:00 Green US 1 3 June, 23 2016 00:00:00 Red Japan 1 2 June, 23 2016 00:00:00 Red US 1 4 June, 24 2016 00:00:00 Green US 1 4 June, 24 2016 00:00:00 Red Japan 0 2 June, 24 2016 00:00:00 Red US 1 5
试试这个:
SELECT [Date], Color, Country, Sales,
SUM(Sales) OVER(PARTITION BY Color, Country ORDER BY [Date] rows unbounded preceding) as RunningTotal
FROM YourTable
ORDER BY [Date], Color
它产生了预期的输出。
[编辑]
如果您正在寻找缺失日期、国家和颜色的解决方案,请试试这个(将 @tmp
替换为您的 table 的名称):
SELECT A.[Date], A.Color, A.Country, COALESCE(B.Sales, 0) AS Sales
, SUM(COALESCE(B.Sales, 0)) OVER(PARTITION BY A.Color, A.Country ORDER BY A.[Date] rows unbounded preceding) as RunningTotal
FROM (
SELECT [Date], Color, Country
FROM (SELECT DISTINCT [Date] FROM @tmp) AS q1 CROSS JOIN
(SELECT DISTINCT Color FROM @tmp) AS q2 CROSS JOIN
(SELECT DISTINCT Country FROM @tmp) AS q3
) AS A
LEFT JOIN @tmp AS B ON A.[Date] = B.[Date] AND A.Color= B.Color AND A.Country = B.Country
ORDER BY A.[Date], A.Color
以上查询产生:
Date Color Country Sales RunningTotal
2016-06-20 Green Japan 0 0
2016-06-20 Green US 1 1
2016-06-20 Red Japan 1 1
2016-06-20 Red US 1 1
2016-06-21 Green US 0 1
2016-06-21 Green Japan 0 0
2016-06-21 Red US 1 2
2016-06-21 Red Japan 0 1
2016-06-22 Green Japan 0 0
2016-06-22 Green US 1 2
2016-06-22 Red Japan 0 1
2016-06-22 Red US 1 3
2016-06-23 Green US 1 3
2016-06-23 Green Japan 0 0
2016-06-23 Red US 1 4
2016-06-23 Red Japan 1 2
2016-06-24 Green Japan 0 0
2016-06-24 Green US 1 4
2016-06-24 Red Japan 0 2
2016-06-24 Red US 1 5
我认为你应该使用左连接而不是内连接
SELECT
t.Date,
t.Color,
t.Country,
t.CumulativeSales
from DiodeSales t
left join
(SELECT
t1.Date,
t1.Color,
t1.Country,
t1.Sales,
SUM(t2.Sales) AS CumulativeSales
FROM DiodeSales AS t1
GROUP BY
t1.Date,
t1.Color,
t1.Country) t2
on
t.Date=t2.date
and t.Color=t2.color
and t.Country=t2.country
试试这个
Select distinct Date into SalesDate From DiodeSales
SELECT S.Date,t.Color,t.Country,t.CumulativeSales
from DiodeSales t left join
(SELECt t1.Date,t1.Color,t1.Country,t1.Sales,
SUM(t2.Sales) AS CumulativeSales FROM DiodeSales AS t1
GROUP BY
t1.Date,
t1.Color,
t1.Country) t2 on
S.Date=t2.date
and t.Color=t2.color
and t.Country=t2.country
join
SalesDate S
on t.date=S.date