顺序求和值重新开始每次更改的总和

时间:2014-08-07 14:23:08

标签: sql-server

我在列中有这些值:      1      1      1      -1      -1      1      1      1      1      1      -1      1

我需要一个查询,它将返回第一个连续的值之和,然后返回下一个,依此类推,每次该值与执行新总和之前的值不同。 根据这个例子,这些连续总和的结果如下:

 3
 -2
 5
 -1
 1

在速度和资源使用方面,通过每个值循环并计算每个总和或者可以在一个查询中完成此操作的最佳方法是什么? 有什么想法吗?

---------- EDITION ------------

我设法使用row_number over partition添加以下列:

COL A   COL B
1       1
2       1
3       1
1      -1
2      -1
1       1
2       1
3       1

....等等

这有什么帮助吗?

---------第二版--------- 我有这个:

  SELECT  ROW_NUMBER() OVER (PARTITION BY T.RES ORDER BY T.ID_Test_Case DESC) AS GRP,
          T.RES,
          T.ID_Test_Case
  FROM    (
            SELECT TEST_CASE.ID_Test_Case,
                   (CASE WHEN TEST_RESULT.Name = TR2.Name THEN 1 ELSE -1 END) AS RES
            FROM   (Join from all tables needed)
            WHERE (All Conditions) ) T
            ORDER BY T.ID_Test_Case DESC
          )

这是我正在检索值1和-1的地方,由于order by子句,它总是被排序相同。我只能使用Test_Case.ID来订购并且是一个独特的领域...希望这有帮助

3 个答案:

答案 0 :(得分:3)

使用递归CTE:

DECLARE @tmp TABLE
(
    RowID   int IDENTITY(1,1),
    Value   int
)

INSERT INTO @tmp
    VALUES (1),(1),(1),(-1),(-1),(1),(1),(1),(1),(1),(-1),(1)

;WITH
    Groups AS
    (
        SELECT      RowID       As GroupID,
                    RowID       As RowID,
                    Value       As Value
        FROM        @tmp
        WHERE       RowID = 1
        UNION ALL
        SELECT      CASE
                        WHEN this.Value = prev.Value THEN prev.GroupID
                        ELSE this.RowID
                    END         As GroupID,
                    this.RowID  As RowId,
                    this.Value  AS Value
        FROM        @tmp    this
        INNER JOIN  Groups  prev    ON this.RowID = prev.RowID + 1
    )

SELECT      SUM(Value)
FROM        Groups
GROUP BY    GroupID

<强>解释

  1. 您想要的是将行分成顺序相等的值组。这里的RowID用作行号。

  2. CTE以RowID = 1开头,创建了一个新的&#34;组&#34;

  3. UNION ALL递归地添加RowID = 2, 3, 4等。每次迭代时,它会考虑其值是否等于前一行的值。如果是,则使用与前一行相同的GroupID。如果没有,则使用其RowID启动新组。

  4. 我们现在只需要总结每组的价值即可得到你想要的东西。

  5. 要查看此工作的内部结构,请将最终SELECT替换为SELECT * FROM Groups

答案 1 :(得分:2)

应该是不言自明的。不优雅,但会完成工作。

Create Table _Numbercolumn (val int)
Create Table _RandValues ( random int)
Create Table _Sum([sum] int)

insert into _RandValues values(1)
insert into _RandValues values(-1)
while ( select COUNT(val) from _Numbercolumn ) < 100
BEGIN 
    Insert into _numbercolumn select top 1 random from _RandValues order by NEWID()
END


DECLARE Number_Cursor CURSOR FOR SELECT val from _Numbercolumn
DECLARE @CurrentSum int, @CursorVal int
OPEN Number_Cursor;
Set @CurrentSum = 0 

FETCH NEXT FROM Number_Cursor into @CursorVal;
WHILE @@FETCH_STATUS = 0
    BEGIN
    IF SIGN(@CurrentSum) <> SIGN(@CursorVal)
        BEGIN
        INSERT INTO _Sum Values(@CurrentSum)
        SET @CurrentSum = @CursorVal    
        END
    ELSE
        SET @CurrentSum = @CurrentSum + @CursorVal
    FETCH NEXT FROM Number_Cursor into @CursorVal;
    END;
CLOSE Number_Cursor;
DEALLOCATE Number_Cursor;
GO

Select * from _Sum

答案 2 :(得分:1)

以下是与您的设置相同的唯一排序:

SELECT  *
INTO    #t
FROM    (VALUES (1,1),(2,1),(3,1),(4,-1),(5,-1),(6,1),(7,1),(8,1),(9,1),(10,1),(11,-1),(12,1)) AS t(RowNbr, VALUE);

现在,使用上面的内容,您可以在一个查询中完成(可能有更好的方法,但这应该足够了):

;WITH ChangingRows AS (
    SELECT  t1.RowNbr, t1.Value, ROW_NUMBER() OVER (ORDER BY t1.RowNbr) AS Ord
    FROM    #t t1
            LEFT JOIN #t t2 ON t1.RowNbr = t2.RowNbr - 1 
    WHERE   t1.Value != ISNULL(t2.Value, 0)
)
SELECT  (c1.RowNbr - ISNULL(c2.RowNbr, 0)) * c1.Value as Total
FROM    ChangingRows c1
        LEFT JOIN ChangingRows c2 ON c2.Ord = c1.Ord - 1;