Rya*_*yan 5 sql-server-2008 sql-server running-totals
我需要在滚动总和计算上设置一个下限。例如,与
PKID NumValue GroupID
----------------------------
1 -1 1
2 -2 1
3 5 1
4 -7 1
5 1 2
Run Code Online (Sandbox Code Playgroud)
我想拥有:
PKID RollingSum GroupID
----------------------------- ## Explanation:
1 0 1 ## 0 - 1 < 0 => 0
2 0 1 ## 0 - 2 < 0 => 0
3 5 1 ## 0 + 5 > 0 => 5
4 0 1 ## 5 - 7 < 0 => 0
Run Code Online (Sandbox Code Playgroud)
当添加一个负数将导致总和为负时,将激活限制以将结果设置为零。后续的加法应该基于这个调整后的值,而不是原来的滚动总和。
应该使用加法来达到预期的结果。如果第四个数字从 -7 变为 -3,则第四个结果应该是 2 而不是 0
如果可以提供单个金额而不是几个滚动数字,那也是可以接受的。我可以使用存储过程来实现非负加法,但这太低级了。
现实生活中的问题是我们将下订单记录为正数,取消订单为负数。由于连接问题,客户可能cancel
会多次单击该按钮,这将导致记录多个负值。在计算我们的收入时,“零”需要作为销售额的界限。
这个业务应用程序绝对是愚蠢的,但我对此无能为力。对于这个问题,请只考虑 DBA 可以使用的解决方案。
我希望每个GroupID
最多五十行。
这是我想出的一个递归 CTE 示例(似乎有效)。使用 Row_Number() OVER 创建一个没有间隙的序列号。我不知道它对您的数据的表现如何,但值得尝试。
--Set up demo data
IF OBJECT_ID('tempdb..#temp') IS NOT NULL
drop table #temp
go
create table #temp (PKID int, NumValue int, GroupID int)
insert into #temp values
(1,-1,1), (3,-2,1), (5,5,1), (7,-3,1), (9,1,2)
--here is the real code
;
with RowNumberAddedToTemp as
(
SELECT
ROW_NUMBER() OVER(ORDER BY PKID ASC) AS rn,
* from #temp
)
,x
AS (
SELECT PKID --Anchor row
,NumValue
,RunningTotal = CASE
WHEN NumValue < 0 --if initial value less than zero, make zero
THEN 0
ELSE NumValue
END
,GroupID
,rn
FROM RowNumberAddedToTemp
WHERE rn = 1
UNION ALL
SELECT y.PKID
,y.NumValue
,CASE
WHEN x.GroupID <> y.groupid --did GroupId change?
THEN CASE
WHEN y.NumValue < 0 --if value is less than zero, make zero
THEN 0
ELSE y.numvalue --start new groupid totals
END
WHEN x.RunningTotal + y.NumValue < 0 --If adding the current row makes the total < 0, make zero
THEN 0
ELSE x.RunningTotal + y.NumValue --Add to the running total for the current groupid
END
,y.Groupid
,y.rn
FROM x
INNER JOIN RowNumberAddedToTemp AS y ON y.rn = x.rn + 1
)
SELECT PKID
,Numvalue
,RunningTotal
,GroupID
FROM x
ORDER BY PKID
OPTION (MAXRECURSION 10000);
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1907 次 |
最近记录: |