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 le suivant.
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
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
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 plateformes de base de données. Lorsqu'il existe une meilleure solution disponible pour votre plate-forme spécifique (par exemple, celle de Gareth), utilisez-la!
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 complète en 34 secondes plus de 5 millions de lignes pour moi.
Merci à Peso, qui a commenté le fil de discussion de l’équipe SQL mentionné dans une autre réponse.
À partir de SQL Server 2012, cela pourrait être simple:
SELECT id, SomeNumt, sum(SomeNumt) OVER (ORDER BY id) as CumSrome FROM @t
parce que la clause ORDER BY
pour SUM
par défaut signifie RANGE UNBOUNDED PRECEDING AND CURRENT ROW
pour le cadre de fenêtre ("Remarques générales" sur https://msdn.Microsoft.com/en-us/library/ms189461.aspx )
Permet de créer d'abord une table 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
je me joins à la même table (SELF Joining)
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
on y va maintenant il suffit de résumer la Somevalue de t2 et on aura la réponse
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
FOR SQL SERVER 2012 et supérieur (performances bien meilleures)
Select c1.ID, c1.SomeValue,
SUM (SomeValue) OVER (ORDER BY c1.ID )
From CumulativeSum c1
Order By c1.id Asc
Résultat désiré
ID SomeValue CumlativeSumValue
1 10 10
2 2 12
3 6 18
4 10 28
Drop Table CumulativeSum
Effacer la table factice
Une version CTE, juste pour le fun:
;
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.
Résultats:
id SomeNumt MySum
----------- ----------- -----------
1 10 10
2 12 22
3 3 25
4 15 40
5 23 63
Réponse tardive mais montrant une possibilité supplémentaire ...
La génération de la somme cumulative peut être davantage optimisée avec la logique CROSS APPLY
.
Fonctionne mieux que les INNER JOIN
et OVER Clause
lors de l'analyse du plan de requête réel ...
/* 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
Select *, (Select SUM(SOMENUMT)
From @t S
Where S.id <= M.id)
From @t M
Une implémentation CTE beaucoup plus rapide est disponible dans cet excellent article: 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.*
</ code>
Ci-dessus (Pre-SQL12) nous voyons des exemples comme celui-ci: -
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
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
La solution SQL qui combine "ROWS ENTRE PRECEDENT ET ROW ACTUEL SANS LIMITE" 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 "Certains fabricants" (exemple). Sinon, aucune incrémentation 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 ça:
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 ce qui précède: Il commence le décompte de "certains fabricants" avec 0, un fabricant est trouvé et nous faisons +1. Pour l'utilisateur 1, MakerC est trouvé, donc nous ne faisons pas +1, mais le décompte vertical de Some Maker reste bloqué sur 2 jusqu'à la ligne suivante .
Je suis au travail, je ne veux pas de mérite sur cette réponse, dites simplement merci et montrez mon exemple au cas où quelqu'un se trouverait dans la même situation. J'essayais de combiner SUM et PARTITION, mais l'incroyable syntaxe "ROWS ENTRE DES PRECEDENTS NON LIMITES ET UN ROW ACTUEL" a complété la tâche.
Merci! Groaker
Essaye ça:
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
Essaye ça
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;
Sans utiliser aucun type de salaire cumulatif JOIN pour une personne récupérée à l'aide de la requête suivante:
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