อัปเดตหากคุณใช้ SQL Server 2012 โปรดดู: https://stackoverflow.com/a/10309947
ปัญหาคือว่าการดำเนินการของ SQL Server ของประโยคกว่าจะค่อนข้าง จำกัด
Oracle (และ ANSI-SQL) ช่วยให้คุณทำสิ่งต่าง ๆ เช่น:
SELECT somedate, somevalue,
SUM(somevalue) OVER(ORDER BY somedate
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
AS RunningTotal
FROM Table
SQL Server ไม่ได้ช่วยแก้ปัญหาให้คุณ ลำไส้ของฉันบอกฉันว่านี่เป็นหนึ่งในกรณีที่หายากที่เคอร์เซอร์เร็วที่สุดแม้ว่าฉันจะต้องทำการเปรียบเทียบกับผลลัพธ์ที่ยิ่งใหญ่
เคล็ดลับการอัปเดตมีประโยชน์ แต่ฉันรู้สึกว่ามันค่อนข้างบอบบาง ดูเหมือนว่าหากคุณกำลังอัปเดตตารางเต็มจะดำเนินการต่อไปตามลำดับของคีย์หลัก ดังนั้นหากคุณตั้งวันที่เป็นคีย์หลักจากน้อยไปมากคุณจะprobably
ปลอดภัย แต่คุณต้องพึ่งพารายละเอียดการใช้งาน SQL Server ที่ไม่มีเอกสาร (เช่นถ้าแบบสอบถามสิ้นสุดลงด้วยการดำเนินการโดยสอง procs ฉันสงสัยว่าจะเกิดอะไรขึ้นดู: MAXDOP):
ตัวอย่างการทำงานเต็ม:
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
คุณขอมาตรฐานนี่คือการลดลง
วิธีที่ปลอดภัยที่สุดในการทำสิ่งนี้คือเคอร์เซอร์มันเป็นลำดับความสำคัญเร็วกว่าแบบสอบถามย่อยที่สัมพันธ์กันของการเข้าร่วมข้าม
วิธีที่เร็วที่สุดที่แน่นอนคือเคล็ดลับการอัพเดท ข้อกังวลเดียวของฉันคือว่าฉันไม่แน่ใจว่าภายใต้สถานการณ์ทั้งหมดการปรับปรุงจะดำเนินการในลักษณะเชิงเส้น ไม่มีสิ่งใดในแบบสอบถามที่บอกอย่างชัดเจน
บรรทัดล่างสำหรับรหัสการผลิตฉันจะใช้เคอร์เซอร์
ข้อมูลการทดสอบ:
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
ทดสอบ 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
ทดสอบ 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
ทดสอบ 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
ทดสอบ 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