如何计算 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