Как получить суммарную сумму

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

Ответ 1

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 |

Изменить: это обобщенное решение, которое будет работать на большинстве платформ db. Когда есть лучшее решение для вашей конкретной платформы (например, gareth's), используйте его!

Ответ 2

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

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

Ответ 3

Версия 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

Ответ 4

Позволяет сначала создать таблицу с фиктивными данными →

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)

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

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

Ответ 6

Поздний ответ, но показывая еще одну возможность...

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

В этой превосходной должности есть намного более быстрая реализация 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.*

код >

Ответ 8

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

Ответ 9

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

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

Выше (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

Попробуйте это

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

Попробуйте следующее:

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

Решение SQL, сочетающее "ROWS BETWEEN UNOCUNDED PRECEDING AND CURRENT ROW" и "SUM", сделало именно то, чего я хотел достичь. Большое вам спасибо!

Если это может помочь кому-то, вот мое дело. Я хотел бы кумулировать +1 в столбце всякий раз, когда создатель найден как "Some Maker" (пример). Если нет, нет инкремента, но показывается результат предыдущего приращения.

Итак, этот кусок 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 найден, и мы делаем +1. Для пользователя 1, MakerC найден таким образом, что мы не делаем +1, но вместо вертикального подсчета Some Maker застряли до 2 до следующей строки. Разделение осуществляется пользователем, поэтому, когда мы меняем пользователя, кумулятивный счет возвращается к нулю.

Я на работе, я не хочу никаких заслуг в этом ответе, просто скажите спасибо и покажите мой пример, если кто-то окажется в той же ситуации. Я пытался объединить SUM и PARTITION, но удивительный синтаксис "ROWS BETWEEN UNOCUNDED PRECEDING AND CURRENT ROW" завершил задачу.

Спасибо! Groaker

Ответ 14

Без использования каких-либо суммарной зарплаты JOIN для извлечения человека с использованием следующего запроса:

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