代码之家  ›  专栏  ›  技术社区  ›  ps.

如何求累计和

  •  144
  • ps.  · 技术社区  · 16 年前
    declare  @t table
        (
            id int,
            SomeNumt int
        )
    
    insert into @t
    select 1,10
    union
    select 2,12
    union
    select 3,3
    union
    select 4,15
    union
    select 5,23
    
    
    select * from @t
    

    上面的选择返回以下信息。

    id  SomeNumt
    1   10
    2   12
    3   3
    4   15
    5   23
    

    我如何得到以下信息

    id  srome   CumSrome
    1   10  10
    2   12  22
    3   3   25
    4   15  40
    5   23  63
    
    14 回复  |  直到 8 年前
        1
  •  181
  •   D'Arcy Rittich    10 年前
    select t1.id, t1.SomeNumt, SUM(t2.SomeNumt) as sum
    from @t t1
    inner join @t t2 on t1.id >= t2.id
    group by t1.id, t1.SomeNumt
    order by t1.id
    

    SQL Fiddle example

    产量

    | ID | SOMENUMT | SUM |
    -----------------------
    |  1 |       10 |  10 |
    |  2 |       12 |  22 |
    |  3 |        3 |  25 |
    |  4 |       15 |  40 |
    |  5 |       23 |  63 |
    

    编辑: 这是一个通用的解决方案,适用于大多数数据库平台。当您的特定平台(如Gareth)有更好的解决方案时,请使用它!

        2
  •  152
  •   Davidjb    8 年前

    最新版本的SQL Server(2012)允许以下操作。

    SELECT 
        RowID, 
        Col1,
        SUM(Col1) OVER(ORDER BY RowId ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS Col2
    FROM tablehh
    ORDER BY RowId
    

    SELECT 
        GroupID, 
        RowID, 
        Col1,
        SUM(Col1) OVER(PARTITION BY GroupID ORDER BY RowId ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS Col2
    FROM tablehh
    ORDER BY RowId
    

    这样更快。对于我来说,分区版本在34秒内完成,超过500万行。

    感谢peso,他对另一个答案中提到的sql团队线程发表了评论。

        3
  •  17
  •   Jibin Balachandran    9 年前

    对于SQL Server 2012以后的版本,这可能很容易:

    SELECT id, SomeNumt, sum(SomeNumt) OVER (ORDER BY id) as CumSrome FROM @t
    

    因为 ORDER BY 条款 SUM 默认方式 RANGE UNBOUNDED PRECEDING AND CURRENT ROW 窗框(“一般说明”见 https://msdn.microsoft.com/en-us/library/ms189461.aspx )

        4
  •  12
  •   Neeraj Prasad Sharma    8 年前

    让我们首先使用虚拟数据创建表-->

    Create Table CUMULATIVESUM (id tinyint , SomeValue tinyint)
    
    **Now let put some data in the table**
    
    Insert Into CUMULATIVESUM
    
    Select 1, 10 union 
    Select 2, 2  union
    Select 3, 6  union
    Select 4, 10 
    

    这里我加入同一个表(自加入)

    Select c1.ID, c1.SomeValue, c2.SomeValue
    From CumulativeSum c1,  CumulativeSum c2
    Where c1.id >= c2.ID
    Order By c1.id Asc
    

    结果:

    ID  SomeValue   SomeValue
    1   10          10
    2   2           10
    2   2            2
    3   6           10
    3   6            2
    3   6            6
    4   10          10
    4   10           2
    4   10           6
    4   10          10
    

    现在我们把t2的某个值求和,得到ans

    Select c1.ID, c1.SomeValue, Sum(c2.SomeValue) CumulativeSumValue
    From CumulativeSum c1,  CumulativeSum c2
    Where c1.id >= c2.ID
    Group By c1.ID, c1.SomeValue
    Order By c1.id Asc
    

    对于SQL Server 2012及更高版本(性能更佳)

    Select c1.ID, c1.SomeValue, 
    SUM (SomeValue) OVER (ORDER BY c1.ID )
    From CumulativeSum c1
    Order By c1.id Asc
    

    期望结果

    ID  SomeValue   CumlativeSumValue
    1   10          10
    2   2           12
    3   6           18
    4   10          28
    
    Drop Table CumulativeSum
    

    清除Dummytable

        5
  •  10
  •   Damir Sudarevic    16 年前

    CTE版本,只是为了好玩:

    ;
    WITH  abcd
            AS ( SELECT id
                       ,SomeNumt
                       ,SomeNumt AS MySum
                 FROM   @t
                 WHERE  id = 1
                 UNION ALL
                 SELECT t.id
                       ,t.SomeNumt
                       ,t.SomeNumt + a.MySum AS MySum
                 FROM   @t AS t
                        JOIN abcd AS a ON a.id = t.id - 1
               )
      SELECT  *  FROM    abcd
    OPTION  ( MAXRECURSION 1000 ) -- limit recursion here, or 0 for no limit.
    

    返回:

    id          SomeNumt    MySum
    ----------- ----------- -----------
    1           10          10
    2           12          22
    3           3           25
    4           15          40
    5           23          63
    
        6
  •  6
  •   Aditya    10 年前

    回答晚了,但又显示出一种可能性…

    使用 CROSS APPLY 逻辑。

    INNER JOIN 和; OVER Clause 当分析实际查询计划时…

    /* Create table & populate data */
    IF OBJECT_ID('tempdb..#TMP') IS NOT NULL
    DROP TABLE #TMP 
    
    SELECT * INTO #TMP 
    FROM (
    SELECT 1 AS id
    UNION 
    SELECT 2 AS id
    UNION 
    SELECT 3 AS id
    UNION 
    SELECT 4 AS id
    UNION 
    SELECT 5 AS id
    ) Tab
    
    
    /* Using CROSS APPLY 
    Query cost relative to the batch 17%
    */    
    SELECT   T1.id, 
             T2.CumSum 
    FROM     #TMP T1 
             CROSS APPLY ( 
             SELECT   SUM(T2.id) AS CumSum 
             FROM     #TMP T2 
             WHERE    T1.id >= T2.id
             ) T2
    
    /* Using INNER JOIN 
    Query cost relative to the batch 46%
    */
    SELECT   T1.id, 
             SUM(T2.id) CumSum
    FROM     #TMP T1
             INNER JOIN #TMP T2
                     ON T1.id > = T2.id
    GROUP BY T1.id
    
    /* Using OVER clause
    Query cost relative to the batch 37%
    */
    SELECT   T1.id, 
             SUM(T1.id) OVER( PARTITION BY id)
    FROM     #TMP T1
    
    Output:-
      id       CumSum
    -------   ------- 
       1         1
       2         3
       3         6
       4         10
       5         15
    
        7
  •  3
  •   Ritesh Khatri    12 年前

    Select *, (Select SUM(SOMENUMT) From @t S Where S.id <= M.id) From @t M

        8
  •  2
  •   cezarm    14 年前

    在这篇优秀的文章中有一个更快的CTE实现: http://weblogs.sqlteam.com/mladenp/archive/2009/07/28/SQL-Server-2005-Fast-Running-Totals.aspx

    这个线程中的问题可以这样表示:

        DECLARE @RT INT
        SELECT @RT = 0
    
        ;
        WITH  abcd
                AS ( SELECT TOP 100 percent
                            id
                           ,SomeNumt
                           ,MySum
                           order by id
                   )
          update abcd
          set @RT = MySum = @RT + SomeNumt
          output inserted.*
    

        9
  •  1
  •   Mark    12 年前

    创建表后-

    select 
        A.id, A.SomeNumt, SUM(B.SomeNumt) as sum
        from @t A, @t B where A.id >= B.id
        group by A.id, A.SomeNumt
    
    order by A.id
    
        10
  •  1
  •   Julian    9 年前

    上面(pre-sql12)的例子如下:

    SELECT
        T1.id, SUM(T2.id) AS CumSum
    FROM 
        #TMP T1
        JOIN #TMP T2 ON T2.id < = T1.id
    GROUP BY
        T1.id
    

    效率更高…

    SELECT
        T1.id, SUM(T2.id) + T1.id AS CumSum
    FROM 
        #TMP T1
        JOIN #TMP T2 ON T2.id < T1.id
    GROUP BY
        T1.id
    
        11
  •  0
  •   p.s.w.g    12 年前

    试试这个

    select 
        t.id,
        t.SomeNumt, 
        sum(t.SomeNumt) Over (Order by t.id asc Rows Between Unbounded Preceding and Current Row) as cum
    from 
        @t t 
    group by
        t.id,
        t.SomeNumt
    order by
        t.id asc;
    
        12
  •  0
  •   mirabilos Jai Prakash Rai    11 年前

    试试这个:

    CREATE TABLE #t(
     [name] varchar NULL,
     [val] [int] NULL,
     [ID] [int] NULL
    ) ON [PRIMARY]
    
    insert into #t (id,name,val) values
     (1,'A',10), (2,'B',20), (3,'C',30)
    
    select t1.id, t1.val, SUM(t2.val) as cumSum
     from #t t1 inner join #t t2 on t1.id >= t2.id
     group by t1.id, t1.val order by t1.id
    
        13
  •  0
  •   Groaker    10 年前

    sql解决方案将“前一行和当前行之间的行”和“和”结合起来,实现了我想要的目标。 非常感谢!

    如果能帮上忙的话,这是我的案子。每当一个制造者被发现是“某个制造者”(示例)时,我想在一个列中累积+1。如果不是,则不显示增量,而是显示以前的增量结果。

    所以这段sql:

    SUM( CASE [rmaker] WHEN 'Some Maker' THEN  1 ELSE 0 END) 
    OVER 
    (PARTITION BY UserID ORDER BY UserID,[rrank] ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS Cumul_CNT
    

    让我得到这样的东西:

    User 1  Rank1   MakerA      0  
    User 1  Rank2   MakerB      0  
    User 1  Rank3   Some Maker  1  
    User 1  Rank4   Some Maker  2  
    User 1  Rank5   MakerC      2
    User 1  Rank6   Some Maker  3  
    User 2  Rank1   MakerA      0  
    User 2  Rank2   SomeMaker   1  
    

    上面的解释:它以0开始“some maker”的计数,找到some maker,我们做+1。对于用户1,makerc被找到,所以我们不做+1,但是一些maker的垂直计数在下一行之前被固定在2。 分区是按用户进行的,所以当我们更改用户时,累计计数会回到零。

    我在工作,我不想在这个答案上有任何价值,只要说谢谢,并展示我的例子,以防有人在同样的情况下。我试着把sum和partition结合起来,但是令人惊奇的语法“rows between unbounded preceding and current row”完成了任务。

    谢谢! 探索者

        14
  •  0
  •   Paolo Forgia panoet    9 年前

    不使用任何类型的联接累积薪资,而是使用以下查询获取人员:

    SELECT * , (
      SELECT SUM( salary ) 
      FROM  `abc` AS table1
      WHERE table1.ID <=  `abc`.ID
        AND table1.name =  `abc`.Name
    ) AS cum
    FROM  `abc` 
    ORDER BY Name
    
    推荐文章