如何计算SQL上总销售额的每日快照?

时间:2016-06-24 05:35:25

标签: sql sql-server cumulative-sum

我有一张桌子(让我们称之为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            

我希望能够有一个额外的列,告诉我在此之前我们已售出多少二极管。因此,例如,使用上述数据,{6月23日,红色,1,美国}行的总销售额将为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个销售额,因此它们不会具有与之关联的累计值。例如,考虑上表的结果:

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中没有办法做到这一点,但是有可能在这个结果表中填充某些国家没有销售日期的值吗?对于某个国家/地区,起始表每天至少会有一列。

我知道我可以写一个简单的

SELECT SUM(Sales) FROM DiodeSales
WHERE Date <= @someDate AND Color = @someColor AND Country = @someCountry

获取此信息,但这是针对一个必须以这种方式格式化的表,以供其他已经制作的软件使用。

编辑:有人提到这是计算Running Total in SQL Server的潜在副本,但该帖子仅在计算运行总和时解决了效率问题。我已经有各种方法来计算这笔钱,但我正在寻找一种方法来解决在该国没有销售的日子里缺少日/国家组合的问题。对于上面的示例,固定查询将返回以下内容:

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

3 个答案:

答案 0 :(得分:3)

试试这个:

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替换为您的表格名称):

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

答案 1 :(得分:2)

我认为你应该使用左连接而不是内连接

  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

答案 2 :(得分:0)

试试这个

 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