Update, если вы работаете в SQL Server 2012 смотрите: https://stackoverflow.com/a/10309947
Проблема заключается в том, что реализация SQL Server клаузулы Over является somewhat limited.
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 (также, если запрос заканчивается выполняется двумя проками Интересно, что произойдет, см: 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
You попросил бенчмарк, это низкая оценка.
Самый быстрый способ сделать это будет курсором, он на порядок быстрее, чем коррелированный подзапрос кросс-соединения.
Абсолютным самым быстрым способом является трюк UPDATE. Меня беспокоит только то, что я не уверен, что при любых обстоятельствах обновление будет происходить линейным образом. В запросе явно ничего не говорится.
Нижняя линия, для производственного кода Я бы пошел с помощью курсора.
Тестовые данные:
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
http://blogs.msdn.com/sqltips/archive/2005/07/20/441053.aspx Добавить заказ к вашему обновлению ... установить и получить гарантию. –
Но заказ не может быть применен к заявлению UPDATE ... не так ли? – codeulike
Правильно, моя ошибка. –