繁体   English   中英

sql动态累积和 - SQL Server

[英]sql dynamic cumulative sum - SQL Server

我有一张这样的桌子

+------+--------+
|   ID | Salary | 
+------+--------+
| 1    |    100 |
| 2    |     40 |
| 3    |     30 |
| 4    |     40 |
| 5    |     90 |
| 6    |    160 |
| 7    |     70 |
| 8    |     40 |
| 9    |     20 |
| 10   |     10 |
| 11   |    200 | 
| 12   |     50 |
+------+--------+

我可以做正常的累计总和,但我需要的东西异于常人CUMULATIVE SUM 如果累计金额比最后一笔金额高%50 ,则下一个累计金额将从该值开始

+------+--------+---------------+
|   ID | Salary | Running Total |
+------+--------+---------------+
| 1    |    100 |           100 |
| 2    |     40 |           140 |
| 3    |     30 |           170 |
| 4    |     40 |           210 |
| 5    |     90 |           300 |
| 6    |    160 |           460 |
| 7    |     70 |           230 |
| 8    |     40 |           270 |
| 9    |     20 |           290 |
| 10   |     10 |           300 |
| 11   |    200 |           500 |
| 12   |     50 |           250 |
+------+--------+---------------+

我想要这样的输出。

试试这个:

SELECT ID , Salary,SUM(Salary) OVER(ORDER BY ID)Running Total
FROM Your_Table

更新答案:

我花了一整天才得到这个:

DECLARE @TAB TABLE(ID INT, SALARY INT)

INSERT INTO @TAB VALUES(1 ,100)
INSERT INTO @TAB VALUES(2 , 40)
INSERT INTO @TAB VALUES(3 , 30)
INSERT INTO @TAB VALUES(4 , 40)
INSERT INTO @TAB VALUES(5 , 90)
INSERT INTO @TAB VALUES(6 ,160)
INSERT INTO @TAB VALUES(7 , 70)
INSERT INTO @TAB VALUES(8 , 40)
INSERT INTO @TAB VALUES(9 , 20)
INSERT INTO @TAB VALUES(10, 10)
INSERT INTO @TAB VALUES(11,200)
INSERT INTO @TAB VALUES(12, 50)


DECLARE @MIN INT, @MAX INT, @PreVal INT, @CurVal INT, @OldVal INT,@NextVal,  INT, @ExistVal INT
DECLARE @TABLE1 TABLE(ID INT, Sal INT, RunTotal INT)

INSERT INTO @TABLE1 (Id, Sal)
SELECT * FROM @TAB

SELECT @MIN=MIN(ID),@MAX=MAX(ID) FROM @TAB

WHILE(@MIN<=@MAX)
BEGIN
    SELECT @NextVal=SALARY FROM @TAB WHERE ID=@MIN
    SELECT @ExistVal=SALARY FROM @TAB WHERE ID=@MIN-1
    SELECT @OldVal=RunTotal FROM @TABLE1 WHERE ID=@MIN-1
    SELECT @PreVal=RunTotal FROM @TABLE1 WHERE ID=@MIN-2

    IF(@OldVal>@PreVal+(@PreVal/2))
    BEGIN
        SELECT @CurVal = @NextVal+@ExistVal
    END
    ELSE
    BEGIN
        SELECT @CurVal=ISNULL(@OldVal,0)+@NextVal-- FROM @TABLE1 WHERE ID=@MIN
    END

    UPDATE @TABLE1 SET RunTotal=@CurVal WHERE ID=@MIN
    SELECT @MIN=@MIN+1
END

SELECT * FROM @TABLE1

结果:

ID  Sal RunTotal
1   100 100
2   40  140
3   30  170
4   40  210
5   90  300
6   160 460
7   70  230
8   40  270
9   20  290
10  10  300
11  200 500
12  50  250

如果有人有更好的答案,请在评论中提及。

回答你的第二个问题:

DECLARE @MIN INT, @MAX INT, @PreVal INT, @CurVal INT, @OldVal INT,@NextVal INT, @ExistVal INT
DECLARE @TABLE1 TABLE(ID INT, Sal INT, RunTotal INT,TimesGen INT)

INSERT INTO @TABLE1 (Id, Sal)
SELECT * FROM @TAB

SELECT @MIN=MIN(ID),@MAX=MAX(ID) FROM @TAB

WHILE(@MIN<=@MAX)
BEGIN
    SELECT @NextVal=SALARY FROM @TAB WHERE ID=@MIN
    SELECT @ExistVal=SALARY FROM @TAB WHERE ID=@MIN-1
    SELECT @OldVal=RunTotal FROM @TABLE1 WHERE ID=@MIN-1
    SELECT @PreVal=RunTotal FROM @TABLE1 WHERE ID=@MIN-2

    IF(@OldVal>@PreVal+(@PreVal/2))
    BEGIN
        SELECT @CurVal = @NextVal--+@ExistVal
        UPDATE @TABLE1 SET TimesGen=1 WHERE ID=@MIN 
    END
    ELSE
    BEGIN
        SELECT @CurVal=ISNULL(@OldVal,0)+@NextVal-- FROM @TABLE1 WHERE ID=@MIN
        UPDATE @TABLE1 SET TimesGen=ISNULL((SELECT TimesGen FROM @TABLE1 WHERE ID=@MIN-1),0)+1 WHERE ID=@MIN
    END

    UPDATE @TABLE1 SET RunTotal=@CurVal WHERE ID=@MIN
    SELECT @MIN=@MIN+1
END

SELECT ID,Sal Salary
    ,'('+CAST(RunTotal AS VARCHAR)+'/'+CAST(TimesGen AS VARCHAR)+') '+CAST(CAST(RunTotal*1.0/TimesGen AS NUMERIC(8,1)) AS VARCHAR) MovingAvg
    ,CAST(RunTotal*1.0/TimesGen AS NUMERIC(8,1))MovingAvg1
FROM @TABLE1

输出:

ID  Salary  MovingAvg
1   100     (100/1) 100.0
2   40      (140/2) 70.0
3   30      (170/3) 56.7
4   40      (210/4) 52.5
5   90      (300/5) 60.0
6   160     (460/6) 76.7
7   70      (230/2) 115.0
8   40      (270/3) 90.0
9   20      (290/4) 72.5
10  10      (300/5) 60.0
11  200     (500/6) 83.3
12  50      (250/2) 125.0

顺便说一下,我怎样才能将RunTotal列更改为Moving Average列。我想计算该行到该行的总平均值

以相同值为例;

+------+--------+----------+-----+
|   ID | Salary |MovingAvg | Flag|/* if the movavg increasing rate higher */
+------+--------+----------+-----+/* than %50 get 1 to flag, else 0 */
| 1    |    100 |      100 |  0  |
| 2    |     40 |       70 |  0  |/* (100+40)/2=70 */
| 3    |     30 |     56.6 |  0  |/* (100+40+30)/3=56.6 */
| 4    |     40 |     52.5 |  0  |/* (100+40+30+40)/4=52.5 */
| 5    |     90 |       60 |  0  |/* (100+40+30+40+90)/5=60 */
| 6    |    270 |       95 |  1  |/*MovAvg increasing rate is more than%50*/
| 7    |     70 |       70 |  0  |/* starting from this line*/
| 8    |     40 |       55 |  0  |/* (70+40)/2 */
| 9    |     10 |       40 |  0  |
| 10   |     60 |       45 |  0  |
| 11   |    300 |       96 |  1  |/*MovAvg increasing rate is more than%50*/
| 12   |     50 |       50 |  0  |
| 13   |     60 |       55 |  0  |/* (50+60)/2 */
+------+--------+----------+-----+

基于递归CTE的答案

select * 
from @T t
order by t.id;
with cteRN as 
( select t.*, ROW_NUMBER() over (order by t.id) as rn 
  from @T t
)
, cte as 
( select t.id, t.salary, t.salary as running, flag = 0, t.rn
  from cteRN t
  where t.rn = 1
  union all 
  select t.id, t.salary
       , case when c.flag = 1 then t.salary + c.salary
              else                 c.running + t.salary
         end 
       , case when t.salary > c.running / 2 then 1
              else 0
         end
       , t.rn
  from cte c 
  join cteRN t
    on t.rn = c.rn + 1
)
select t.id, t.salary, t.running 
from cte t
order by t.id;

id          salary
----------- -----------
1           100
2           40
3           30
4           40
5           90
6           160
7           70
8           40
9           20
10          10
11          200
12          50

id          running     running
----------- ----------- -----------
1           100         100
2           140         140
3           170         170
4           210         210
5           300         300
6           460         460
7           230         230
8           270         270
9           290         290
10          300         300
11          500         500
12          250         250

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM