Накопление в SQL
У меня есть запрос с результатами, как ID, значение. Я хочу получить значения в порядке их идентификаторов, а также рассчитать накопленное значение в другом столбце. взгляните на мой упрощенный код:
declare @TempTable Table
(
ID int,
Value int
)
insert into @TempTable values
(1, 10),
(2, -15),
(3, 12),
(4, 18),
(5, 5)
select t1.ID, t1.Value, SUM(t2.Value) AccValue from @TempTable t1
inner join @TempTable t2 on t1.ID >= t2.ID
group by t1.ID, t1.Value
order by t1.ID
Result:
ID Value AccValue
1 10 10
2 -15 -5
3 12 7
4 18 25
5 5 30
Я пришел к выводу, что для этой цели нужно использовать внутреннее соединение результата с самим собой. Но для огромного количества данных это явно проблема низкой производительности.
Есть ли другая альтернатива для этого?
3 ответа
В версии 2012 вы можете использовать:
SELECT
id,
Value,
AccValue = SUM(Value) OVER (ORDER BY ID
ROWS BETWEEN UNBOUNDED PRECEDING
AND CURRENT ROW)
FROM
@TempTable ;
Для предыдущих версий SQL-сервера см. Мой ответ в этом похожем вопросе: Рекурсивный SQL- Как я могу получить эту таблицу с промежуточным итогом? с помощью курсора.
Более того, перейдите по ссылке на замечательную статью rtemp, в которой подробно рассматриваются различные методы вычисления rtemp: лучшие подходы для расчета rtemp итогов - обновлено для SQL Server 2012
Вы можете использовать рекурсию:
;WITH x AS
(
SELECT
[ID],
[Value],
bal=[Value]
FROM Table1
WHERE [ID] = 1
UNION ALL
SELECT
y.[ID],
y.[Value],
x.bal+(y.[Value]) as bal
FROM x INNER JOIN Table1 AS y
ON y.[ID] = x.[ID] + 1
)
SELECT
[ID],
[Value],
AccValue= bal
FROM x
order by ID
OPTION (MAXRECURSION 10000);
Общий способ SQL сделать это с помощью коррелированного подзапроса (по крайней мере, я думаю, что это самый чистый способ):
select t.*,
(select sum(t2.value)
from @TempTable t2
where t2.ID <= t.ID
) AccValue
from @TempTable t
SQL Server 2012 имеет функцию накопительной суммы:
select t.*,
sum(t.value) over (order by t.id) as AccValue
from @TempTable t