Am trying to calculate running total. But it should reset when the cummulative sum greater than another column value
我试图计算运行总量。但是当累计和大于另一列值时,它应该重置
create table #reset_runn_total
(
id int identity(1,1),
val int,
reset_val int
)
insert into #reset_runn_total
values
(1,10),
(8,12),(6,14),(5,10),(6,13),(3,11),(9,8),(10,12)
sample data
样本数据
+----+-----+-----------+
| id | val | reset_val |
+----+-----+-----------+
| 1 | 1 | 10 |
| 2 | 8 | 12 |
| 3 | 6 | 14 |
| 4 | 5 | 10 |
| 5 | 6 | 13 |
| 6 | 3 | 11 |
| 7 | 9 | 8 |
| 8 | 10 | 12 |
+----+-----+-----------+
Expected result
预期结果
+----+-----+-----------------+-------------+
| id | val | reset_val | Running_tot |
+----+-----+-----------------+-------------+
| 1 | 1 | 10 | 1 |
| 2 | 8 | 12 | 9 | --1+8
| 3 | 6 | 14 | 15 | --1+8+6 -- greater than reset val
| 4 | 5 | 10 | 5 | --reset
| 5 | 6 | 13 | 11 | --5+6
| 6 | 3 | 11 | 14 | --5+6+3 -- greater than reset val
| 7 | 9 | 8 | 9 | --reset -- greater than reset val
| 8 | 10 | 12 | 10 | --reset
+----+-----+-----------------+-------------+
Query:
查询:
;WITH cte
AS (SELECT id,
val,
reset_val,
val AS running_total
FROM #reset_runn_total
WHERE id = 1
UNION ALL
SELECT r.*,
CASE
WHEN lag(c.running_total + r.val) over(order by r.id) > lag(r.reset_val) over(order by r.id) THEN r.reset_val
ELSE c.running_total + r.val
END
FROM cte c
JOIN #reset_runn_total r
ON r.id = c.id + 1)
SELECT *
FROM cte
obviously lag will not get the previous values any ideas?
显然滞后不会得到以前的价值任何想法?
2 个解决方案
#1
8
Try flag previous row
尝试标记前一行
WITH cte
AS (SELECT id,
val,
reset_val,
val AS running_total,
CASE WHEN val > reset_val THEN 1 ELSE 0 END as flag
FROM #reset_runn_total
WHERE id = 1
UNION ALL
SELECT r.*,
CASE c.flag
WHEN 1 then r.val
ELSE c.running_total + r.val
END,
CASE WHEN CASE c.flag
WHEN 1 then r.val
ELSE c.running_total + r.val
END > r.reset_val
THEN 1 ELSE 0 END
FROM cte c
JOIN #reset_runn_total r
ON r.id = c.id + 1)
SELECT *
FROM cte
#2
1
You can try using a quirky update like this
您可以尝试使用像这样的古怪更新
--- setup
IF OBJECT_ID('tempdb..#reset_runn_total') IS NOT NULL DROP TABLE #reset_runn_total
create table #reset_runn_total(id int identity(1,1) PRIMARY KEY, val int, reset_val int, running_sum int)
insert into #reset_runn_total(val, reset_val) values (1,10),(8,12),(6,14),(5,10),(6,13),(3,11),(9,8),(10,12)
--- use quirky update
DECLARE @running_sum INT
, @temp INT
UPDATE #reset_runn_total
SET @temp = running_sum = COALESCE(@running_sum, 0) + val
, @running_sum = CASE WHEN @temp < reset_val THEN @temp ELSE 0 END
OPTION (FORCE ORDER)
--- dump result
SELECT * FROM #reset_runn_total
Note that CLUSTERED INDEX
on the temp table is required (PK's default type) for OPTION (FORCE ORDER)
to make sense.
请注意,对于OPTION(FORCE ORDER),临时表上的CLUSTERED INDEX是必需的(PK的默认类型)才有意义。
#1
8
Try flag previous row
尝试标记前一行
WITH cte
AS (SELECT id,
val,
reset_val,
val AS running_total,
CASE WHEN val > reset_val THEN 1 ELSE 0 END as flag
FROM #reset_runn_total
WHERE id = 1
UNION ALL
SELECT r.*,
CASE c.flag
WHEN 1 then r.val
ELSE c.running_total + r.val
END,
CASE WHEN CASE c.flag
WHEN 1 then r.val
ELSE c.running_total + r.val
END > r.reset_val
THEN 1 ELSE 0 END
FROM cte c
JOIN #reset_runn_total r
ON r.id = c.id + 1)
SELECT *
FROM cte
#2
1
You can try using a quirky update like this
您可以尝试使用像这样的古怪更新
--- setup
IF OBJECT_ID('tempdb..#reset_runn_total') IS NOT NULL DROP TABLE #reset_runn_total
create table #reset_runn_total(id int identity(1,1) PRIMARY KEY, val int, reset_val int, running_sum int)
insert into #reset_runn_total(val, reset_val) values (1,10),(8,12),(6,14),(5,10),(6,13),(3,11),(9,8),(10,12)
--- use quirky update
DECLARE @running_sum INT
, @temp INT
UPDATE #reset_runn_total
SET @temp = running_sum = COALESCE(@running_sum, 0) + val
, @running_sum = CASE WHEN @temp < reset_val THEN @temp ELSE 0 END
OPTION (FORCE ORDER)
--- dump result
SELECT * FROM #reset_runn_total
Note that CLUSTERED INDEX
on the temp table is required (PK's default type) for OPTION (FORCE ORDER)
to make sense.
请注意,对于OPTION(FORCE ORDER),临时表上的CLUSTERED INDEX是必需的(PK的默认类型)才有意义。