簡體   English   中英

在T-SQL中運行SUM

[英]Running SUM in T-SQL

對不起,不好的話題,但我不確定該怎么稱呼。

我有一張桌子,看起來像這樣:

+-----++-----+
| Id  ||Count|
+-----++-----+
| 1   || 1   |
+-----++-----+
| 2   || 5   |
+-----++-----+
| 3   || 8   |
+-----++-----+
| 4   || 3   |
+-----++-----+
| 5   || 6   |
+-----++-----+
| 6   || 8   |
+-----++-----+
| 7   || 3   |
+-----++-----+
| 8   || 1   |
+-----++-----+

我正在嘗試從此表中進行選擇,其中每當row1 + row2 + row3(等)的總和達到10時,它就是“ HIT”,並且計數重新開始。

要求的輸出:

+-----++-----++-----+
| Id  ||Count|| HIT |
+-----++-----++-----+
| 1   || 1   ||  N  | Count = 1
+-----++-----++-----+
| 2   || 5   ||  N  | Count = 6
+-----++-----++-----+
| 3   || 8   ||  Y  | Count = 14 (over 10)
+-----++-----++-----+
| 4   || 3   ||  N  | Count = 3
+-----++-----++-----+
| 5   || 6   ||  N  | Count = 9
+-----++-----++-----+
| 6   || 8   ||  Y  | Count = 17 (over 10..)
+-----++-----++-----+
| 7   || 3   ||  N  | Count = 3
+-----++-----++-----+
| 8   || 1   ||  N  | Count = 4
+-----++-----++-----+

如何做到這一點,並獲得最佳性能? 我不知道..

這個評論太長了。

您無法使用窗口/分析功能執行此操作,因為斷點是事先未知的。 有時,可以計算斷點。 但是,在這種情況下,斷點取決於先前值的非線性函數(我現在想不出比“非線性”更好的詞)。 也就是說,有時將“ 1”添加到較早的值對當前行的計算的影響為零。 有時會產生很大的影響。 這意味着計算必須從頭開始並遍歷數據。

A小調修改問題利用這樣的功能是可解的。 相反,如果問題是要為每個組結轉多余的金額(而不是重新開始總和),則可以使用累積總和(和其他一些技巧)解決問題。

遞歸查詢(其他人提供的)或順序操作是解決此問題的最佳方法。 不幸的是,它沒有基於集合的方法來解決它。

您可以使用遞歸查詢

請注意以下查詢,假設id值均按順序排列,否則,請使用ROW_NUMBER()創建新的id

WITH cte AS (
  SELECT id, [Count], [Count] AS total_count
  FROM Table1 
  WHERE id = 1
  UNION ALL
  SELECT t2.id,t2.[Count], CASE WHEN t1.total_count >= 10 THEN t2.[Count] ELSE t1.total_count + t2.[Count] END
  FROM Table1 t2
  INNER JOIN cte t1 
    ON t2.id = t1.id + 1
  )
SELECT *
FROM cte
ORDER BY id

SQL小提琴

我真的希望有人可以向我們展示如果可以使用直接的窗口函數來做到這一點。 那才是真正的挑戰。

同時,這是我將使用遞歸的方法。 這處理序列中的間隙,並處理第一行的邊緣情況已經>= 10

我還添加了maxrecursion提示以刪除默認的遞歸限制。 但老實說,我不知道它將在處理大量數據時運行得如何。

with NumberedRows as (
  select Id, Cnt,
         row_number() over(order by id) as rn
    from CountTable
), RecursiveCTE as (
  select Id, Cnt, rn, 
         case when Cnt >= 10 then 0 else Cnt end as CumulativeSum,
         case when Cnt >= 10 then 'Y' else 'N' end as hit
    from NumberedRows
   where rn = 1
  union all
  select n.Id, n.Cnt, n.rn,
         case when (n.Cnt + r.CumulativeSum) >= 10 then 0 else n.Cnt + r.CumulativeSum end as CumulativeSum,
         case when (n.Cnt + r.CumulativeSum) >= 10 then 'Y' else 'N' end as hit
    from RecursiveCTE r
    join NumberedRows n
      on n.rn = r.rn + 1
)
select Id, Cnt, hit
from RecursiveCTE
order by Id
option (maxrecursion 0)

SQLFiddle演示

如何使用“運行總計”:

DECLARE @Data TABLE(
    Id INT
    ,SubTotal INT
)


INSERT INTO @Data
    VALUES(1, 5)

INSERT INTO @Data
    VALUES(2, 3)

INSERT INTO @Data
    VALUES(3, 4)

INSERT INTO @Data
    VALUES(4, 4)

INSERT INTO @Data
    VALUES(5, 7)

DECLARE @RunningTotal INT = 0
DECLARE @HitCount INT = 0    

SELECT  
        @RunningTotal = CASE WHEN @RunningTotal < 10 THEN @RunningTotal + SubTotal ELSE SubTotal END
        ,@HitCount = @HitCount + CASE WHEN @RunningTotal >= 10 THEN 1 ELSE 0 END
        FROM @Data ORDER BY Id

SELECT @HitCount -- Outputs 2

重新閱讀問題后,我看到這不符合要求的輸出-我將保留答案,因為它可能對尋找不需要此類型問題的整體解決方案示例的人有用每行標有Y或N。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM