Sqlserver
 sql >> Teknologi Basis Data >  >> RDS >> Sqlserver

Hitung Total Berjalan di SQL Server

Perbarui , jika Anda menjalankan SQL Server 2012 lihat:https://stackoverflow.com/a/10309947

Masalahnya adalah implementasi SQL Server dari klausa Over agak terbatas.

Oracle (dan ANSI-SQL) memungkinkan Anda melakukan hal-hal seperti:

 SELECT somedate, somevalue,
  SUM(somevalue) OVER(ORDER BY somedate 
     ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) 
          AS RunningTotal
  FROM Table

SQL Server tidak memberi Anda solusi bersih untuk masalah ini. Firasat saya memberi tahu saya bahwa ini adalah salah satu kasus langka di mana kursor adalah yang tercepat, meskipun saya harus melakukan beberapa pembandingan pada hasil yang besar.

Trik pembaruan berguna tetapi saya merasa ini cukup rapuh. Tampaknya jika Anda memperbarui tabel lengkap maka itu akan dilanjutkan dalam urutan kunci utama. Jadi, jika Anda menetapkan tanggal sebagai kunci utama naik, Anda akan probably berhati-hatilah. Tetapi Anda mengandalkan detail implementasi SQL Server yang tidak berdokumen (juga jika kueri akhirnya dilakukan oleh dua proc, saya ingin tahu apa yang akan terjadi, lihat:MAXDOP):

Contoh kerja penuh:

drop table #t 
create table #t ( ord int primary key, total int, running_total int)

insert #t(ord,total)  values (2,20)
-- notice the malicious re-ordering 
insert #t(ord,total) values (1,10)
insert #t(ord,total)  values (3,10)
insert #t(ord,total)  values (4,1)

declare @total int 
set @total = 0
update #t set running_total = @total, @total = @total + total 

select * from #t
order by ord 

ord         total       running_total
----------- ----------- -------------
1           10          10
2           20          30
3           10          40
4           1           41

Anda meminta patokan ini adalah lowdown.

Cara AMAN tercepat untuk melakukan ini adalah Kursor, ini adalah urutan besarnya lebih cepat daripada sub-kueri cross-join yang berkorelasi.

Cara tercepat mutlak adalah trik UPDATE. Satu-satunya kekhawatiran saya adalah bahwa saya tidak yakin bahwa dalam semua keadaan pembaruan akan berjalan secara linier. Tidak ada dalam kueri yang secara eksplisit mengatakan demikian.

Intinya, untuk kode produksi saya akan menggunakan kursor.

Data pengujian:

create table #t ( ord int primary key, total int, running_total int)

set nocount on 
declare @i int
set @i = 0 
begin tran
while @i < 10000
begin
   insert #t (ord, total) values (@i,  rand() * 100) 
    set @i = @i +1
end
commit

Tes 1:

SELECT ord,total, 
    (SELECT SUM(total) 
        FROM #t b 
        WHERE b.ord <= a.ord) AS b 
FROM #t a

-- CPU 11731, Reads 154934, Duration 11135 

Tes 2:

SELECT a.ord, a.total, SUM(b.total) AS RunningTotal 
FROM #t a CROSS JOIN #t b 
WHERE (b.ord <= a.ord) 
GROUP BY a.ord,a.total 
ORDER BY a.ord

-- CPU 16053, Reads 154935, Duration 4647

Tes 3:

DECLARE @TotalTable table(ord int primary key, total int, running_total int)

DECLARE forward_cursor CURSOR FAST_FORWARD 
FOR 
SELECT ord, total
FROM #t 
ORDER BY ord


OPEN forward_cursor 

DECLARE @running_total int, 
    @ord int, 
    @total int
SET @running_total = 0

FETCH NEXT FROM forward_cursor INTO @ord, @total 
WHILE (@@FETCH_STATUS = 0)
BEGIN
     SET @running_total = @running_total + @total
     INSERT @TotalTable VALUES(@ord, @total, @running_total)
     FETCH NEXT FROM forward_cursor INTO @ord, @total 
END

CLOSE forward_cursor
DEALLOCATE forward_cursor

SELECT * FROM @TotalTable

-- CPU 359, Reads 30392, Duration 496

Tes 4:

declare @total int 
set @total = 0
update #t set running_total = @total, @total = @total + total 

select * from #t

-- CPU 0, Reads 58, Duration 139


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Nilai pencocokan klausa SQL WHERE dengan spasi tambahan

  2. Bagaimana cara mengembalikan beberapa set hasil dengan SqlCommand?

  3. Cara Mengembalikan Hasil Kueri sebagai Daftar Dipisahkan Koma di SQL Server – STRING_AGG()

  4. SQL Server SHOWPLAN_TEXT

  5. Haruskah saya menggunakan !=atau <> untuk tidak sama di T-SQL?