2017-02-07 1 views
10

누적 합계를 계산하려합니다.다른 컬럼을 기반으로 누적 합계를 재설정하십시오.

;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 

분명히 뜻을 지연 : 또 다른 열 값보다 cummulative 합보다

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) 

샘플 데이터

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

예상 결과가

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

쿼리 때 그것을 다시 설정해야합니다 ~하지 마라. 이전 값은 어떤 아이디어입니까?

답변

8

보십시오 플래그 이전 행

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

와우 .. Sum() Over() 창 집계를 사용하여이 작업을 수행 할 수 있습니까? –

+0

또는 '재귀 적 CTE'를 사용하지 않습니까? –

+1

재귀가 피할 수없는 것처럼 보입니다 ... – Serg

1
당신은 이해하기 OPTION (FORCE ORDER) 위해 (PK의 기본 유형) 임시 테이블에 CLUSTERED INDEX이 필요하다는 것을이

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

주와 같은 기발한 업데이트를 사용 시도 할 수 있습니다

.

+0

답변 해 주셔서 감사합니다. 나는 하나 이상의 그룹을 위해 이것을해야만한다. 단순화를 위해 단 하나의 그룹에 대한 샘플 데이터를 추가했습니다. 두 개 이상의 그룹에 대해서는 작동하지 않습니다 –

+0

기발한 업데이트를 위해 모든 전제 조건 (최소 10 개)을 확인하십시오. http://www.sqlservercentral.com/articles/T-SQL/68467/ – Serg

관련 문제