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
die obige Auswahl gibt mir Folgendes zurück.
id SomeNumt
1 10
2 12
3 3
4 15
5 23
Wie bekomme ich das Folgende?
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
Ausgabe
| ID | SOMENUMT | SUM |
-----------------------
| 1 | 10 | 10 |
| 2 | 12 | 22 |
| 3 | 3 | 25 |
| 4 | 15 | 40 |
| 5 | 23 | 63 |
Edit: Dies ist eine verallgemeinerte Lösung, die auf den meisten Datenbankplattformen funktioniert. Wenn für Ihre spezifische Plattform (z. B. Gareths) eine bessere Lösung verfügbar ist, verwenden Sie sie!
Die neueste Version von SQL Server (2012) ermöglicht Folgendes.
SELECT
RowID,
Col1,
SUM(Col1) OVER(ORDER BY RowId ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS Col2
FROM tablehh
ORDER BY RowId
oder
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
Das geht noch schneller. Die partitionierte Version führt in 34 Sekunden über 5 Millionen Zeilen für mich aus.
Vielen Dank an Peso, der den SQL-Team-Thread kommentierte, auf den in einer anderen Antwort verwiesen wird.
Für SQL Server 2012 kann es einfach sein:
SELECT id, SomeNumt, sum(SomeNumt) OVER (ORDER BY id) as CumSrome FROM @t
weil ORDER BY
-Klausel für SUM
standardmäßig RANGE UNBOUNDED PRECEDING AND CURRENT ROW
für Fensterrahmen bedeutet ("Allgemeine Bemerkungen" unter https://msdn.Microsoft.com/en-us/library/ms189461.aspx )
Lass zuerst eine Tabelle mit Dummy-Daten erstellen ->
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
hier füge ich dieselbe Tabelle hinzu (SELF Joining)
Select c1.ID, c1.SomeValue, c2.SomeValue
From CumulativeSum c1, CumulativeSum c2
Where c1.id >= c2.ID
Order By c1.id Asc
ERGEBNIS:
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
hier gehen wir jetzt nur das Somevalue von t2 zusammen und wir bekommen die 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
FÜR SQL SERVER 2012 und höher (viel besser)
Select c1.ID, c1.SomeValue,
SUM (SomeValue) OVER (ORDER BY c1.ID )
From CumulativeSum c1
Order By c1.id Asc
Erwünschtes Ergebnis
ID SomeValue CumlativeSumValue
1 10 10
2 2 12
3 6 18
4 10 28
Drop Table CumulativeSum
Lösche die Dummy-Tabelle
Eine CTE-Version, nur zum Spaß:
;
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.
Kehrt zurück:
id SomeNumt MySum
----------- ----------- -----------
1 10 10
2 12 22
3 3 25
4 15 40
5 23 63
Späte Antwort, zeigt aber noch eine Möglichkeit ...
Die Generierung von kumulativen Summen kann mit der CROSS APPLY
-Logik weiter optimiert werden.
Funktioniert besser als INNER JOIN
& OVER Clause
, wenn der tatsächliche Abfrageplan analysiert wird ...
/* 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
In diesem ausgezeichneten Beitrag ist eine viel schnellere CTE-Implementierung verfügbar: http://weblogs.sqlteam.com/mladenp/archive/2009/07/28/SQL-Server-2005-Fast-Running-Totals.aspx
Das Problem in diesem Thread kann folgendermaßen ausgedrückt werden:
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>
Oben (Pre-SQL12) sehen wir Beispiele wie diese: -
SELECT
T1.id, SUM(T2.id) AS CumSum
FROM
#TMP T1
JOIN #TMP T2 ON T2.id < = T1.id
GROUP BY
T1.id
Effizienter...
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
Sobald die Tabelle erstellt ist -
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
Die SQL-Lösung, die "ROWS ZWISCHEN UNBEGRENZTEN PRECEDING UND CURRENT ROW" und "SUM" kombiniert, hat genau das gemacht, was ich erreichen wollte .... Vielen Dank!
Wenn es jemandem helfen kann, war hier mein Fall. Ich wollte +1 in einer Spalte kumulieren, wenn ein Hersteller als "Some Maker" (Beispiel) gefunden wird. Wenn nicht, kein Inkrement, sondern vorheriges Inkrementergebnis anzeigen.
Also dieses Stück 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
Erlaubte mir so etwas zu bekommen:
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
Erklärung von oben: Es beginnt die Zählung von "Some Maker" mit 0, Some Maker wird gefunden und wir machen +1. Für Benutzer 1 wird MakerC gefunden, so dass wir nicht +1 geben, sondern stattdessen die vertikale Anzahl von Some Maker bis zur nächsten Zeile auf 2 gehalten wird .. Die Partitionierung erfolgt nach Benutzer.
Ich bin auf der Arbeit, ich möchte keinen Verdienst für diese Antwort, sagen Sie einfach Danke und zeigen Sie mein Beispiel, falls sich jemand in derselben Situation befindet. Ich habe versucht, SUMME und PARTITION zu kombinieren, aber die erstaunliche Syntax "ROWS BETWEEN UNBUNDED PRECEDING AND CURRENT ROW" vervollständigte die Aufgabe.
Danke! Groaker
Versuche dies:
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
Versuche dies
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;
Ohne Verwendung eines kumulativen JOIN-Gehalts für eine Person wird mithilfe der folgenden Abfrage abgerufen:
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