Cara mendapatkan jumlah kumulatif

186
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

pilih di atas mengembalikan saya yang berikut.

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

Bagaimana saya mendapatkan yang berikut ini:

id  srome   CumSrome
1   10  10
2   12  22
3   3   25
4   15  40
5   23  63
ps.
sumber
5
Menjalankan menjalankan total dalam T-SQL tidak sulit, ada banyak jawaban yang benar, kebanyakan dari mereka cukup mudah. Apa yang tidak mudah (atau bahkan mungkin saat ini) adalah menulis kueri sebenarnya dalam T-SQL untuk menjalankan total yang efisien. Mereka semua O (n ^ 2), meskipun mereka bisa dengan mudah menjadi O (n), kecuali bahwa T-SQL tidak mengoptimalkan untuk kasus ini. Anda bisa mendapatkan O (n) menggunakan kursor dan / atau loop sementara, tetapi kemudian Anda menggunakan kursor. ( Blech! )
RBarryYoung

Jawaban:

226
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

Contoh SQL Fiddle

Keluaran

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

Sunting: ini adalah solusi umum yang akan bekerja di sebagian besar platform db. Ketika ada solusi yang lebih baik tersedia untuk platform spesifik Anda (misalnya, Gareth's), gunakan!

RedFilter
sumber
12
@ Franklin Hanya hemat biaya untuk meja kecil. Biaya tumbuh sebanding dengan kuadrat jumlah baris. SQL Server 2012 memungkinkan ini dilakukan jauh lebih efisien.
Martin Smith
3
FWIW, buku-buku jari saya dipukul ketika melakukan ini oleh DBA. Saya pikir alasannya menjadi sangat mahal, sangat cepat. Yang sedang berkata, ini adalah pertanyaan wawancara yang hebat, karena sebagian besar analis data / ilmuwan harus menyelesaikan masalah ini sekali atau dua kali :)
BenDundee
@ BenDundee Setuju - Saya cenderung memberikan solusi SQL umum yang akan bekerja pada sebagian besar platform db. Seperti biasa, ketika ada pendekatan yang lebih baik tersedia, misalnya, Gareth, gunakan itu!
RedFilter
199

Versi terbaru dari SQL Server (2012) memungkinkan yang berikut ini.

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

atau

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

Ini bahkan lebih cepat. Versi yang dipartisi selesai dalam 34 detik lebih dari 5 juta baris untuk saya.

Terima kasih kepada Peso, yang mengomentari utas Tim SQL yang disebut dalam jawaban lain.

Gareth Adamson
sumber
22
Untuk singkatnya, Anda dapat menggunakan ROWS UNBOUNDED PRECEDINGbukan ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW.
Dan
1
Catatan: Jika kolom yang Anda ingin jumlahkan secara kumulatif itu sendiri sudah merupakan jumlah atau jumlah, Anda bisa membungkus semuanya sebagai permintaan dalam atau Anda benar-benar dapat melakukannya SUM(COUNT(*)) OVER (ORDER BY RowId ROWS UNBOUNDED PRECEDING) AS CumulativeSum. Tidak segera jelas bagi saya jika itu akan berhasil tetapi itu berhasil :-)
Simon_Weaver
Tersedia dalam PostgreSQL pada 8.4: postgresql.org/docs/8.4/sql-select.html
ADJenks
27

Untuk SQL Server 2012 dan seterusnya, bisa mudah:

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

karena ORDER BYklausa untuk SUMsecara default berarti RANGE UNBOUNDED PRECEDING AND CURRENT ROWuntuk bingkai jendela ("Keterangan Umum" di https://msdn.microsoft.com/en-us/library/ms189461.aspx )

Andrew Karakotov
sumber
13

Versi CTE, hanya untuk bersenang-senang:

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

Pengembalian:

id          SomeNumt    MySum
----------- ----------- -----------
1           10          10
2           12          22
3           3           25
4           15          40
5           23          63
Damir Sudarevic
sumber
13

Mari kita pertama-tama membuat tabel dengan data dummy ->

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 

di sini saya bergabung dengan tabel yang sama (SELF Joining)

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

HASIL:

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

di sini kita pergi sekarang jumlah saja Nilai t2 dan kita akan mendapatkan 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

UNTUK SQL SERVER 2012 dan di atasnya (Performa yang jauh lebih baik)

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

Hasil yang diinginkan

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

Drop Table CumulativeSum

Bersihkan dummytable

Neeraj Prasad Sharma
sumber
harap edit jawaban Anda dan format kode untuk membuatnya dapat dibaca
kleopatra
Bagaimana jika nilai mi "ID" diulang? (mereka jelas bukan kunci utama di meja saya) Saya belum bisa mengadaptasi pertanyaan ini untuk kasus itu?
penuhi
AFAIK Anda memerlukan id unik untuk jumlah kumulatif, dan Anda bisa mendapatkannya menggunakan row_number. periksa kode di bawah ini:; dengan NewTBLWITHUNiqueID sebagai (pilih row_number () di atas (diurutkan berdasarkan id, nilai tertentu) UniqueID, * Dari CUMULATIVESUMwithoutPK)
Neeraj Prasad Sharma
Terima kasih @NeerajPrasadSharma, saya benar-benar menggunakan rank()perintah lain dan klausa untuk menyelesaikannya.
penuhi
5

Jawaban terlambat tetapi menunjukkan satu kemungkinan lagi ...

Jumlah kumulatif jumlah dapat lebih dioptimalkan dengan CROSS APPLYlogika.

Bekerja lebih baik daripada INNER JOIN& OVER Clausesaat dianalisis rencana kueri yang sebenarnya ...

/* 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
Aditya
sumber
1
Saya tidak dibujuk. "Biaya kueri relatif terhadap bets" adalah hal yang tidak berarti untuk membandingkan kinerja kueri. Biaya kueri adalah perkiraan yang digunakan oleh perencana kueri untuk dengan cepat menimbang berbagai rencana dan memilih yang paling murah, tetapi biaya itu adalah untuk membandingkan rencana untuk kueri yang sama , dan tidak relevan atau sebanding di antara kueri , tidak sama sekali. Dataset sampel ini juga terlalu kecil untuk melihat perbedaan yang signifikan antara ketiga metode. Coba lagi dengan baris 1m, lihat rencana eksekusi yang sebenarnya, coba set io statistics ondan bandingkan cpu dan waktu sebenarnya.
Davos
4

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

Ritesh Khatri
sumber
Ini adalah cara yang sangat cerdas untuk mencapai hasil, dan Anda dapat menambahkan beberapa kondisi ke penjumlahan.
RaRdEvA
@RaRdEvA Ini tidak bagus untuk kinerja, ia menjalankannya correlated subqueryuntuk setiap baris dari set hasil, memindai lebih banyak dan lebih banyak baris saat berjalan. Itu tidak menjaga total berjalan dan memindai data sekali seperti fungsi jendela bisa.
Davos
1
@Do Anda benar, jika Anda menggunakannya sangat lambat atas 100.000 catatan.
RaRdEvA
2

Anda dapat menggunakan permintaan sederhana ini untuk perhitungan progresif:

select 
   id
  ,SomeNumt
  ,sum(SomeNumt) over(order by id ROWS between UNBOUNDED PRECEDING and CURRENT ROW) as CumSrome
from @t
Afif Pratama
sumber
1

Setelah tabel dibuat -

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
Porsh
sumber
1

Di atas (Pra-SQL12) kita melihat contoh seperti ini: -

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

Lebih efisien...

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
Julian
sumber
0

Coba ini

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;
bellonid
sumber
Ini berfungsi dengan SQL Server 2012 dan lebih tinggi, 2008 memiliki dukungan terbatas untuk fungsi jendela.
Peter Smit
0

Coba ini:

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
Sachin
sumber
0

Solusi SQL yang menggabungkan "BARIS ANTARA KETEPATAN YANG TIDAK DIUNDING DAN BARIS SAAT INI" dan "SUM" melakukan apa yang ingin saya capai. Terima kasih banyak!

Jika itu dapat membantu siapa pun, ini kasus saya. Saya ingin mengumpulkan +1 di kolom setiap kali pembuat ditemukan sebagai "Pembuat Beberapa" (contoh). Jika tidak, tidak ada kenaikan tetapi tampilkan hasil kenaikan sebelumnya.

Jadi ini bagian dari 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

Izinkan saya untuk mendapatkan sesuatu seperti ini:

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  

Penjelasan di atas: Ini memulai hitungan "beberapa pembuat" dengan 0, Beberapa Pembuat ditemukan dan kami melakukan +1. Untuk Pengguna 1, MakerC ditemukan sehingga kami tidak melakukan +1 tetapi hitungan vertikal Beberapa Pembuat terjebak ke 2 sampai baris berikutnya. Partisi adalah oleh Pengguna sehingga ketika kami mengubah pengguna, jumlah kumulatif kembali ke nol.

Saya di tempat kerja, saya tidak ingin mendapat jawaban apa pun, hanya ucapkan terima kasih dan tunjukkan contoh saya jika seseorang ada dalam situasi yang sama. Saya mencoba untuk menggabungkan SUM dan PARTITION tetapi sintaks yang menakjubkan "BARIS ANTARA PENGECUALIAN YANG TIDAK DITINGGALKAN DAN BARANG LANCAR" menyelesaikan tugas.

Terima kasih! Groaker

Groaker
sumber
0

Tanpa menggunakan segala jenis gaji kumulatif BERGABUNG untuk seseorang yang diambil dengan menggunakan kueri ikuti:

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
Rudar Daman Singla
sumber
0

Untuk Contoh: JIKA Anda memiliki tabel dengan dua kolom, satu adalah ID dan yang kedua adalah angka dan ingin mengetahui jumlah kumulatif.

SELECT ID,Number,SUM(Number)OVER(ORDER BY ID) FROM T
JP
sumber