【问题标题】:How can I calculate daily snapshots of my total sales on SQL?如何计算我在 SQL 上的总销售额的每日快照?
【发布时间】:2016-10-26 15:36:36
【问题描述】:

我有一个表格(我们称之为 DiodeSales),它告诉我我所做的二极管销售总数,按日期、二极管颜色和国家/地区分组。这是此架构的示例:

日期 颜色 国家 销售 2016 年 6 月 20 日 00:00:00 绿色 美国 1 2016 年 6 月 20 日 00:00:00 红日本 1 2016 年 6 月 20 日 00:00:00 红色 美国 1 2016 年 6 月 21 日 00:00:00 红色 美国 1 2016 年 6 月 22 日 00:00:00 绿色 美国 1 2016 年 6 月 22 日 00:00:00 红色 美国 1 2016 年 6 月 23 日 00:00:00 绿色 美国 1 2016 年 6 月 23 日 00:00:00 红日本 1 2016 年 6 月 23 日 00:00:00 红色 美国 1 2016 年 6 月 24 日 00:00:00 绿色 美国 1 2016 年 6 月 24 日 00:00:00 红色 美国 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,因此它们不会有与之关联的累积值。例如,考虑上表的结果:

日期 颜色 国家 销售额 CumulativeSales 2016 年 6 月 20 日 00:00:00 绿色 美国 1 1 2016 年 6 月 20 日 00:00:00 红色日本 1 1 2016 年 6 月 20 日 00:00:00 红色 美国 1 1 2016 年 6 月 21 日 00:00:00 红色 美国 1 2 2016 年 6 月 22 日 00:00:00 绿色 美国 1 2 2016 年 6 月 22 日 00:00:00 红色 美国 1 3 2016 年 6 月 23 日 00:00:00 绿色 美国 1 3 2016 年 6 月 23 日 00:00:00 红色日本 1 2 2016 年 6 月 23 日 00:00:00 红色 美国 1 4 2016 年 6 月 24 日 00:00:00 绿色 美国 1 4 2016 年 6 月 24 日 00:00:00 红色 美国 1 5

如果我要查找与 6 月 24 日对应的日本列,我会一无所获(因为那天没有日本特卖,所以那天没有日本行)。我认为在 SQL 中没有办法做到这一点,但是是否可以在这个结果表中填充某些国家没有销售的日期的值?对于某些国家/地区,起始表每天至少有一列。

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

从 DiodeSales 中选择 SUM(Sales) WHERE 日期 &lt= @someDate AND 颜色 = @someColor AND Country = @someCountry

获取此信息,但这是针对必须以这种方式格式化的表格才能被另一个已制作的软件使用的表格。

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

日期 颜色 国家 销售额 CumulativeSales 2016 年 6 月 20 日 00:00:00 绿色 美国 1 1 2016 年 6 月 20 日 00:00:00 红色日本 1 1 2016 年 6 月 20 日 00:00:00 红色 美国 1 1 2016 年 6 月 21 日 00:00:00 绿色 美国 0 1 2016 年 6 月 21 日 00:00:00 红色日本 0 1 2016 年 6 月 21 日 00:00:00 红色 美国 1 2 2016 年 6 月 22 日 00:00:00 绿色 美国 1 2 2016 年 6 月 22 日 00:00:00 红色日本 0 1 2016 年 6 月 22 日 00:00:00 红色 美国 1 3 2016 年 6 月 23 日 00:00:00 绿色 美国 1 3 2016 年 6 月 23 日 00:00:00 红色日本 1 2 2016 年 6 月 23 日 00:00:00 红色 美国 1 4 2016 年 6 月 24 日 00:00:00 绿色 美国 1 4 2016 年 6 月 24 日 00:00:00 Red Japan 0 2 2016 年 6 月 24 日 00:00:00 红色 美国 1 5

【问题讨论】:

  • 将 sql-server 和 sql-server-2016 添加到标签中。
  • 您使用 SQL-Server-2016 标记您的问题,但 SQLFiddle 是为 MySQL 创建的。哪一个是真的?
  • 那么,你试过我的解决方案了吗?
  • 是的。结果与我在小提琴中发布的解决方案相同。另外,请原谅与 MySQL 小提琴的混淆;该网站的 SQL-Server 选项似乎存在一些问题。

标签: sql sql-server cumulative-sum


【解决方案1】:

试试这个

 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

【讨论】:

    【解决方案2】:

    试试这个:

    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
    

    【讨论】:

    • 这会产生与我的查询相同的输出,因此缺少国家/地区的日子仍然存在。
    • 对不起,在PARTITION BY ...后面加[Date]
    • @FedericoParedes,现在检查我的答案。
    【解决方案3】:

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

      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
    

    【讨论】:

    • 如果有最简单的方法来实现这一点,为什么还要强制开门?
    • 由于我们要加入同一个表,这与 INNER JOIN 查询的行为方式不一样吗?
    猜你喜欢
    • 2022-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-22
    • 1970-01-01
    相关资源
    最近更新 更多