Buscamos en todo el mundo on line para de esta forma regalarte la solución para tu dilema, en caso de dificultades deja la pregunta y te responderemos porque estamos para servirte.
Solución:
Actualizarsi está ejecutando SQL Server 2012, consulte: https://stackoverflow.com/a/10309947
El problema es que la implementación de SQL Server de la cláusula Over es algo limitada.
Oracle (y ANSI-SQL) le permiten hacer cosas como:
SELECT somedate, somevalue,
SUM(somevalue) OVER(ORDER BY somedate
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
AS RunningTotal
FROM Table
SQL Server no le brinda una solución limpia a este problema. Mi instinto me dice que este es uno de esos casos raros en los que un cursor es el más rápido, aunque tendré que hacer algunas evaluaciones comparativas de los grandes resultados.
El truco de actualización es útil, pero siento que es bastante frágil. Parece que si está actualizando una tabla completa, procederá en el orden de la primaria key. Entonces, si establece su fecha como principal key ascendiendo lo harás probably
estar a salvo. Pero confía en un detalle de implementación de SQL Server no documentado (también si la consulta termina siendo realizada por dos procesos, me pregunto qué sucederá, consulte: MAXDOP):
Muestra de trabajo completa:
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
Usted pidió un punto de referencia, este es el detalle.
La forma SEGURA más rápida de hacer esto sería el Cursor, es un orden de magnitud más rápido que la subconsulta correlacionada de unión cruzada.
La forma más rápida absoluta es el truco ACTUALIZAR. Mi única preocupación es que no estoy seguro de que, en todas las circunstancias, la actualización se realice de forma lineal. No hay nada en la consulta que lo diga explícitamente.
En pocas palabras, para el código de producción iría con el cursor.
Datos de prueba:
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
Prueba 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
Prueba 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
Prueba 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
Prueba 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
En SQL Server 2012 puede usar SUM() con la cláusula OVER().
select id,
somedate,
somevalue,
sum(somevalue) over(order by somedate rows unbounded preceding) as runningtotal
from TestTable
Violín SQL
Si bien Sam Saffron hizo un gran trabajo al respecto, aún no proporcionó expresión de tabla común recursiva código para este problema. Y para nosotros que trabajamos con SQL Server 2008 R2 y no con Denali, sigue siendo la forma más rápida de ejecutar el total, es aproximadamente 10 veces más rápido que el cursor en mi computadora de trabajo para 100000 filas, y también es una consulta en línea.
Entonces, aquí está (supongo que hay un ord
columna en la tabla y su número secuencial sin espacios, para un procesamiento rápido también debe haber una restricción única en este número):
;with
CTE_RunningTotal
as
(
select T.ord, T.total, T.total as running_total
from #t as T
where T.ord = 0
union all
select T.ord, T.total, T.total + C.running_total as running_total
from CTE_RunningTotal as C
inner join #t as T on T.ord = C.ord + 1
)
select C.ord, C.total, C.running_total
from CTE_RunningTotal as C
option (maxrecursion 0)
-- CPU 140, Reads 110014, Duration 132
demostración de violín sql
actualizar
yo tambien tenia curiosidad por esto actualizar con variable o actualización peculiar. Por lo general, funciona bien, pero ¿cómo podemos estar seguros de que funciona siempre? bueno, aquí hay un pequeño truco (lo encontré aquí: http://www.sqlservercentral.com/Forums/Topic802558-203-21.aspx#bm981258): solo verifique el actual y el anterior ord
y use 1/0
asignación en caso de que sean diferentes de lo que espera:
declare @total int, @ord int
select @total = 0, @ord = -1
update #t set
@total = @total + total,
@ord = case when ord <> @ord + 1 then 1/0 else ord end,
------------------------
running_total = @total
select * from #t
-- CPU 0, Reads 58, Duration 139
Por lo que he visto, si tiene un índice agrupado/principal adecuado key en su mesa (en nuestro caso sería indexado por ord_id
) la actualización procederá de forma lineal todo el tiempo (nunca se encuentra dividida por cero). Dicho esto, depende de ti decidir si quieres usarlo en el código de producción 🙂
actualizar 2 Estoy vinculando esta respuesta, porque incluye información útil sobre la falta de confiabilidad de la actualización peculiar: concatenación nvarchar/index/nvarchar (max) comportamiento inexplicable.
Sección de Reseñas y Valoraciones
Acuérdate de que te permitimos decir si te fue útil.