Как получить накопительную сумму - PullRequest
154 голосов
/ 23 января 2010
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 ]

189 голосов
/ 23 января 2010
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

выход

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

Редактировать: Это обобщенное решение, которое будет работать на большинстве дБ платформ. Когда есть лучшее решение для вашей конкретной платформы (например, Gareth), используйте его!

161 голосов
/ 11 ноября 2012

Последняя версия 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 секунды для меня более 5 миллионов строк.

Спасибо Peso, который прокомментировал поток SQL Team, упомянутый в другом ответе.

22 голосов
/ 31 августа 2015

Для 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)

11 голосов
/ 23 ноября 2012

Сначала создадим таблицу с фиктивными данными ->

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 

здесь я присоединяюсь к той же таблице (SELF Joining)

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

здесь мы идем теперь, просто сложите Somevalue t2 и мы получим ответ

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

Очистить таблицу

11 голосов
/ 23 января 2010

Версия 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
5 голосов
/ 22 апреля 2016

Поздний ответ, но с еще одной возможностью ...

Генерация накопленной суммы может быть более оптимизирована с помощью логики 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
3 голосов
/ 03 декабря 2013

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

2 голосов
/ 24 мая 2012

В этом замечательном посте доступна гораздо более быстрая реализация CTE: http://weblogs.sqlteam.com/mladenp/archive/2009/07/28/SQL-Server-2005-Fast-Running-Totals.aspx

Проблема в этой теме может быть выражена так: </p> <pre><code> 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.*

1 голос
/ 14 ноября 2016

Выше (до 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
1 голос
/ 04 июля 2013

После создания таблицы -

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...