2017-02-07 6 views
10

Ich versuche, die laufende Summe zu berechnen. Aber es sollte zurückgesetzt, wenn die kumulative Summe größer ist als eine andere Spalte WertReset Laufende Summe basierend auf einer anderen Spalte

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) 

Beispieldaten

+----+-----+-----------+ 
| 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 | 
+----+-----+-----------+ 

Erwartetes Ergebnis

+----+-----+-----------------+-------------+ 
| 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 
+----+-----+-----------------+-------------+ 

Abfrage:

;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 

offenbar Wille hinken nicht bekommen die vorherigen Werte irgendwelche Ideen?

Antwort

8

Try Flagge vorherige Reihe

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 
+0

Wow .. Kann dies mit Sum() Over() Fenster Aggregat erreicht werden? –

+0

Oder ohne 'Recursive CTE' zu verwenden? –

+1

Sieht aus wie Rekursion kann nicht vermieden werden ... – Serg

1

Sie können versuchen, wie dieser

--- 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 

Hinweis eine schrullige Update mit, dass CLUSTERED INDEX auf der temporären Tabelle wird (PK-Standardtyp), die für OPTION (FORCE ORDER) Sinn machen .

+0

Danke für die Antwort. Ich muss das für mehr als eine Gruppe tun. Zur Vereinfachung habe ich Beispieldaten für nur eine Gruppe hinzugefügt. Dies funktioniert nicht für mehr als eine Gruppe –

+0

Stellen Sie sicher, dass Sie alle Voraussetzungen (mindestens 10) für skurriles Update überprüfen. http://www.sqlservercentral.com/articles/T-SQL/68467/ – Serg

Verwandte Themen