【问题标题】:How do I get running total for distinct values in a column如何获得列中不同值的运行总计
【发布时间】:2014-12-15 12:27:46
【问题描述】:

我想按日期范围分组,如下例所示

    Date        ItemNo  Qty
==================================
1/1/2014         101    20
2/1/2014         102    10
3/1/2014         103    5
4/1/2014         104    10
1/1/2014         101    5
2/1/2014         101    10
3/1/2014         102    15
4/1/2014         104    20

我想通过每天按 ItemNo 分组的数量来获得余额,如下所示

Date        ItemNo  Qty
==================================
1/1/2014      101   25
2/1/2014      101   35
2/1/2014      102   10
3/1/2014      102   25
3/1/2014      103   5
4/1/2014      104   30

我知道我可以通过使用游标来解决问题,但我需要另一个解决方案

谢谢

【问题讨论】:

标签: sql sql-server sql-server-2008 cumulative-sum


【解决方案1】:

所以只需使用 SUM

SELECT Date, ItemNo, SUM(Qty)
FROM table
GROUP BY Date, ItemNo

请阅读agregate functionsum

编辑

我接受了你的评论并这样做了:

SELECT a.Date, a.ItemNo, tmp.qty + a.ItemNo
FROM table a
JOIN (SELECT TOP 1 * FROM table t WHERE t.date < a.Date ORDER BY t.date DESC) tmp ON a.ItemNo = tmp.ItemNo 

我现在正在检查它,所以它可能需要一些调整,但我想立即发布它,这样你就会有大致的想法

【讨论】:

  • 我想分组直到日期而不是特定日期。我的意思是项目 x 余额昨天是 5,今天是 10,那么语句将返回昨天的 5 和今天的 15
  • @AhmedFayed 但它是否让你想到了你应该去的女巫之路?
【解决方案2】:

这是您的示例表

SELECT * INTO #TEMP
FROM
(
SELECT  '1/1/2014' [DATE],         101 [ItemNo],    20 QTY
UNION ALL
SELECT '2/1/2014',         102,    10
UNION ALL
SELECT '3/1/2014',         103,    5
UNION ALL
SELECT '4/1/2014',         104,    10
UNION ALL
SELECT '1/1/2014',         101,    5
UNION ALL
SELECT '2/1/2014',        101,    10
UNION ALL
SELECT '3/1/2014',         102,    15
UNION ALL
SELECT '4/1/2014',         104,    20
)TAB

使用Row_Number 获取每个项目的日期编号,在CTE 内执行sum

;WITH CTE1 AS
(
    SELECT ROW_NUMBER() OVER(PARTITION BY  [ItemNo] ORDER BY CAST([DATE] AS DATE))RNO,
    [DATE],[ItemNo],SUM(Qty)Qty
    FROM #TEMP
    GROUP BY [DATE],[ItemNo]
)
SELECT A.RNO,[DATE],[ItemNo],
CASE WHEN RNO=1 THEN Qty 
     ELSE (SELECT SUM(b.Qty)
           FROM   CTE1 b
           WHERE  A.ItemNo=B.ItemNo AND B.RNO<=A.RNO) 
END QTY
FROM CTE1 A
ORDER  BY A.itemno,CAST(A.[DATE] AS DATE);

结果

【讨论】:

  • 这似乎是一个解决方案,但运行了 3 个多小时,然后 sql 崩溃了。我需要一个优化的解决方案,因为 Cursor 会花费更少的时间,但由于性能原因我没有使用它
  • 是的。绝对需要时间。如果您正在处理如此庞大的表,则最好保留一列来存储累积值(运行总计),以便将来可以轻松地从表中查询。如果您使用游标,它会比上面的查询快,因为不需要查询并找到每条记录的总和,因为变量可以在游标执行的每个循环中保持值,但不建议使用游标进行此类一张大桌子。 @艾哈迈德法耶德
  • 我需要为您编写游标查询吗? @艾哈迈德法耶德
  • 如果你得到了你所问问题的答案(即不使用光标查询),你可以将其标记为答案,以便下一个需要此类答案的人可以轻松识别它@Ahmed Fayed
  • 我需要更快的解决方案
【解决方案3】:

这是一个使用递归公用表表达式的解决方案。

不确定它是否会比 Sarath Avanavu 的答案更快,但你可以试试!

样本数据:

DECLARE @t TABLE([Date] DATETIME, ItemNo INT, QTY INT)
INSERT @t
        ( Date, ItemNo, QTY )
          SELECT  '1/1/2014',         101,    20
UNION ALL SELECT '2/1/2014',         102,    10
UNION ALL SELECT '3/1/2014',         103,    5
UNION ALL SELECT '4/1/2014',         104,    10
UNION ALL SELECT '1/1/2014',         101,    5
UNION ALL SELECT '2/1/2014',        101,    10
UNION ALL SELECT '3/1/2014',         102,    15
UNION ALL SELECT '4/1/2014',         104,    20

查询:

;WITH dSum AS (
    SELECT [Date], ItemNo, SUM(QTY) AS QTY 
    FROM @t AS t
    GROUP BY [Date], [ItemNo]
), dSumRN AS (
    SELECT [Date], ItemNo, QTY, ROW_NUMBER() OVER(PARTITION BY ItemNo ORDER BY [Date]) AS rn 
    FROM dSum
), cte AS (
        SELECT [Date], ItemNo, QTY, rn
        FROM  dSumRN
        WHERE rn = 1
    UNION ALL SELECT
        dSumRN.[Date], dSumRN.ItemNo, cte.QTY + dSumRN.QTY AS QTY, cte.rn + 1 AS rn
    FROM cte
        JOIN dSumRN ON cte.ItemNo = dSumRN.ItemNo AND cte.rn + 1 = dSumRN.rn

)
SELECT [Date], [ItemNo], QTY FROM cte
ORDER BY [Date], [ItemNo]
OPTION (MAXRECURSION 1000) -- maximum this can be set to is 32767

【讨论】:

    【解决方案4】:

    下面最简单的查询代码:

    select Date,itemno,
    (select sum(Qty) from #temp where date<=T.date and itemno=T.itemno)
    from #temp T 
    group by Date,itemno order by date
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-28
      • 2019-09-17
      • 2022-12-05
      • 1970-01-01
      相关资源
      最近更新 更多