Comment obtenir la somme cumulée

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

La sélection ci-dessus me renvoie ce qui suit.

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

Comment puis-je obtenir ce qui suit

id  srome   CumSrome
1   10  10
2   12  22
3   3   25
4   15  40
5   23  63
135
demandé sur Paolo Forgia 2010-01-23 00:12:14

14 réponses

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

Exemple de violon SQL

Sortie

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

Edit: c'est une solution généralisée qui fonctionnera sur la plupart des plates-formes db. Quand il y a une meilleure solution disponible pour votre plate-forme spécifique (par exemple, gareth), utilisez-la!

172
répondu RedFilter 2015-09-29 13:54:09

La dernière version de SQL Server (2012) permet ce qui suit.

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

Ou

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

C'est encore plus rapide. La version partitionnée se termine en 34 secondes sur 5 millions de lignes pour moi.

Merci à Peso, qui a commenté le thread de L'équipe SQL mentionné dans une autre réponse.

138
répondu Gareth Adamson 2017-07-25 08:45:35

Pour SQL Server 2012, cela pourrait être facile:

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

, Car ORDER BY clause de SUM par défaut signifie RANGE UNBOUNDED PRECEDING AND CURRENT ROW pour le cadre de fenêtre ("Remarques Générales" à https://msdn.microsoft.com/en-us/library/ms189461.aspx)

15
répondu Andrew Karakotov 2016-12-07 07:23:25

Permet d'abord de créer un tableau avec des données factices -->

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 

Ici, je rejoins la même table (auto-jointure)

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

RÉSULTAT :

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

Ici nous allons maintenant juste la somme de la Somevalue de t2, et nous aurons le sna

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

Pour SQL SERVER 2012 et au-dessus (beaucoup mieux performer)

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

Résultat Souhaité

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

Drop Table CumulativeSum

Effacer le dummytable

11
répondu Neeraj Prasad Sharma 2017-12-12 10:11:51

Une version CTE, juste pour le plaisir:

;
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.

Renvoie:

id          SomeNumt    MySum
----------- ----------- -----------
1           10          10
2           12          22
3           3           25
4           15          40
5           23          63
9
répondu Damir Sudarevic 2010-01-23 18:11:56

Réponse tardive mais montrant une possibilité de plus...

La génération de Somme Cumulative peut être plus optimisée avec la logique CROSS APPLY.

Fonctionne mieux que le INNER JOIN & OVER Clause lors de l'analyse du plan de requête réelle ...

/* 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
6
répondu Aditya 2016-04-22 10:14:49

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

3
répondu Ritesh Khatri 2014-02-21 04:36:33

Il y a une implémentation CTE beaucoup plus rapide disponible dans cet excellent post: http://weblogs.sqlteam.com/mladenp/archive/2009/07/28/SQL-Server-2005-Fast-Running-Totals.aspx

Le problème dans ce fil peut être exprimé comme ceci:

    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.*

2
répondu cezarm 2012-05-23 22:52:17

Une Fois la table créée -

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
1
répondu Porsh 2013-07-04 09:55:53

Ci-dessus (pré-SQL12) nous voyons des exemples comme ceci: -

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

Plus efficace...

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
répondu Julian 2016-11-14 14:29:39

Essayez ceci

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;
0
répondu bellonid 2013-06-28 02:30:57

Essayez ceci:

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
0
répondu Sachin 2015-01-13 11:31:06

La solution SQL qui combine "lignes entre la ligne précédente et la ligne actuelle" et " SUM " a fait exactement ce que je voulais réaliser. Merci beaucoup!

Si cela peut aider quelqu'un, voici mon cas. Je voulais cumuler + 1 dans une colonne chaque fois qu'un fabricant est trouvé comme " un fabricant "(exemple). Sinon, pas d'incrément mais afficher le résultat de l'incrément précédent.

Donc ce morceau de 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

M'a Permis d'obtenir quelque chose comme ceci:

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  

Explication de ci-dessus: il commence le compte de "un fabricant" avec 0, un fabricant est trouvé et nous faisons +1. Pour L'utilisateur 1, MakerC est trouvé donc nous ne faisons pas +1 mais à la place le nombre vertical de certains fabricants est collé à 2 jusqu'à la rangée suivante. Le partitionnement est par utilisateur, donc lorsque nous changeons d'utilisateur, le nombre cumulatif est de retour à zéro.

Je suis au travail, je ne veux aucun mérite sur cette réponse, juste dire merci et montrer mon exemple au cas où quelqu'un est dans la même situation. J'essayais de combiner la somme et la PARTITION mais la syntaxe étonnante " ROWS BETWEEN UNBOUNDED Ligne précédente et actuelle " terminé la tâche.

Merci! Groaker

0
répondu Groaker 2016-05-24 00:28:51

Sans utiliser aucun type de salaire cumulatif de jointure pour une personne en utilisant la requête follow:

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
0
répondu Rudar Daman Singla 2017-06-12 09:34:44