powered by simpleCommunicator - 2.0.59     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Сумма с накоплением?
14 сообщений из 14, страница 1 из 1
Сумма с накоплением?
    #32022955
Sergy
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Добрый день всем!
Когда-то видел решение этой задачи, но поиск нечего не дал.
Может кто знает как грамотно решить задачу сумма с накоплением, т.е.
Есть таблица в которой столбец А содержит числа. Нужно сформировать столбец B, в котором
каждая строчка будет содержать сумму всех предыдущих по столбцу А.
...
Рейтинг: 0 / 0
Сумма с накоплением?
    #32022963
Фотография Александр Степанов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
create table a
(
pk int identity(1,1) not null primary key clustered,
value int not null,
sum_ int null
)
go

insert into a (value) values (20)
insert into a (value) values (30)
insert into a (value) values (10)
insert into a (value) values (60)
insert into a (value) values (30)
insert into a (value) values (80)
insert into a (value) values (70)
insert into a (value) values (50)
go

update a
Set
sum_=(Select SUM(value) from a as sub where sub.pk<=a.pk)
go

Select * from a
go

drop table a
go
...
Рейтинг: 0 / 0
Сумма с накоплением?
    #32022965
qu-qu
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 Александр Степанов

Вообще-то бегать подзапросами по записям и для каждой из них вычислять сумму предыдущих - не самый экономный способ использования ресурсов сервера...


На этот счет здесь давно уже показывали трюк, основанный на интересном свойстве оператора UPDATE в T-SQL:
\nSyntax - UPDATE table_name SET @variable = column = expression

Настолько давно, что я даже забыл - кто именно первым про это упомянул...

В итоге - получим следующее:
create table a
(
pk int identity(1,1) not null primary key clustered,
value int not null,
sum_ int not null -- здесь важно, чтобы слолбец суммы не был null, т.к. без этого трюк не проходит...

)
go
declare @running_sum int
set @running_sum = 0
update a set @running_sum = sum_ = (sum_ + @running_sum) -- (скобки не обязательны)

Особенности "исполнения трюка" - таблица пробегается всего 1 раз, записи перебираются в порядке кластерного индекса (он же - первичный ключ), для временных таблиц, не имеющих ни того, ни другого - в порядке помещения записей во временную таблицу... (т.е. - если есть необходимость считать сумму по датам, а первичный ключ в таблице по ID - грузите промежуточные данные во временную таблицу, указав ORDER BY по дате и все просуммируется правильно).

Удачи!!
...
Рейтинг: 0 / 0
Сумма с накоплением?
    #32022970
Glory
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
1.
update a set @running_sum = sum_ = (sum_ + @running_sum + value )


2.
Можно и не менять условие для поля sum_ на not null, а использовать ISNULL в запросе
update a set @running_sum = sum_ = (ISNULL(sum_, 0) + @running_sum + ISNULL(value, 0))
(IMHO для страховки не повредит)

3.
При использовании такого запроса результат в каждой строке будет содержать значение и из данной строки, что _противоречит начально поставленному условию_, где говориться про сумму только передыдущих строк. Конечно, далее можно использовать запрос SELECT sum_-value FROM a, но все же.
...
Рейтинг: 0 / 0
Сумма с накоплением?
    #32022979
qu-qu
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 Glory

Спасибо за поправку...

(в пылу жажды откровений - совсем позабыл, что самое главное в сумме все же - value )
...
Рейтинг: 0 / 0
Сумма с накоплением?
    #32022988
Владимир Смирнов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Использовать "трюк" с двойным "=" совсем необязательно. Можно так:

declare @running_sum int
set @running_sum = 0
update a set sum_ = @running_sum - value, @running_sum = @running_sum + value --сумма только передыдущих строк
или
update a set @running_sum = @running_sum + value, sum_ = @running_sum --сумма передыдущих строк и текущей
...
Рейтинг: 0 / 0
Сумма с накоплением?
    #32023008
qu-qu
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 Владимир Смирнов

> Использовать "трюк" с двойным "=" совсем необязательно...

Не обязательно... но - желательно...
(иначе - может произойти то, что произошло с вами, т.к. наверняка вы свои запросы выполняли "в голове", а не на SQL-сервере).

Так скажите, пжлст "из головы" - как вы думаете, какие запросы из перечисленных ниже произведут одинаковые действия?

declare @running_sum int
set @running_sum = 0
-- 1.
update a set sum_ = @running_sum, @running_sum = @running_sum + value
set @running_sum = 0
-- 2.
update a set @running_sum = @running_sum + value, sum_ = @running_sum
set @running_sum = 0
-- 3.
update a set sum_ = @running_sum - value, @running_sum = @running_sum + value
-- 4.
update a set @running_sum = @running_sum + value, sum_ = @running_sum - value

(ответом - не мучайтесь... никакие... можете потом сами - на сервере проверить).
...
Рейтинг: 0 / 0
Сумма с накоплением?
    #32023010
qu-qu
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 Владимир Смирнов

М-да...
Вынужден перед вами извиниться, т.к. сам поступил точно по "критикуемой" схеме...

(проверил только 3 запроса, а 4-й дописал в спешке уже в постинге, потому и "set @running_sum = 0" забыл перед ним воткнуть...)

На самом деле - 3-й и 4-й сделают одинаковые действия (и одинаково - неправильные), а 1-й и 2-й - таки разные... (и как раз - нужные)
...
Рейтинг: 0 / 0
Сумма с накоплением?
    #32023059
Владимир Смирнов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
qu-qu.
Я не знаю, на каком основании Вы делаете выводы обо мне. Полагаю, мы не знакомы. Я же сужу по Вашим безапеляционным заявлениям в мой адрес. Такие фразы как "наверняка вы свои запросы выполняли "в голове", а не на SQL-сервере" возможны в двух случаях: либо Вы лично явились свидетелем этой ситуации, либо Вы (возможно по молодости) просто самоуверенный болтун. Ну, первое отпадает, тут уж я свидетель, Вас наверняка рядом не было. Так что остаётся?
Ну а о Ваших запросах. Вот запросы (скопировал из окна QA)

set nocount on
declare @running_sum int
set @running_sum = 0
-- 1.
update a set sum_ = @running_sum, @running_sum = @running_sum + value
select * from a
set @running_sum = 0
-- 2.
update a set @running_sum = @running_sum + value, sum_ = @running_sum
select * from a
set @running_sum = 0
-- 3.
update a set sum_ = @running_sum - value, @running_sum = @running_sum + value
select * from a
set @running_sum = 0
-- 4.
update a set @running_sum = @running_sum + value, sum_ = @running_sum - value
select * from a

А вот результат (также из QA)

pk value sum_
----------- ----------- -----------
1 3 3
2 4 7
3 5 12
4 6 18
5 7 25

pk value sum_
----------- ----------- -----------
1 3 3
2 4 7
3 5 12
4 6 18
5 7 25

pk value sum_
----------- ----------- -----------
1 3 0
2 4 3
3 5 7
4 6 12
5 7 18

pk value sum_
----------- ----------- -----------
1 3 0
2 4 3
3 5 7
4 6 12
5 7 18

Есть ещё вопросы?
...
Рейтинг: 0 / 0
Сумма с накоплением?
    #32023075
qu-qu
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 Владимир Смирнов
> Есть ещё вопросы?

Безусловно - есть... и самый первый - какая у вас версия сервера?
(т.к. я проверял все написанное мной выше на версии 6.5, @@version = "Microsoft SQL Server 6.50 - 6.50.416 (Intel X86) Jan 23 1999 14:10:24 Copyright (c) 1988-1997 Microsoft Corporation"),
и вот - что у меня получилось:

pk Value Sum_
----------- ----------- -----------
1 10 0
2 10 10
3 10 20
4 10 30
5 -10 40
6 -10 30
7 -10 20
8 10 10

pk Value Sum_
----------- ----------- -----------
1 10 10
2 10 20
3 10 30
4 10 40
5 -10 30
6 -10 20
7 -10 10
8 10 20

pk Value Sum_
----------- ----------- -----------
1 10 -10
2 10 0
3 10 10
4 10 20
5 -10 50
6 -10 40
7 -10 30
8 10 0

pk Value Sum_
----------- ----------- -----------
1 10 -10
2 10 0
3 10 10
4 10 20
5 -10 50
6 -10 40
7 -10 30
8 10 0

А насчет вот этого:

> Вы ... просто самоуверенный болтун.

Вроде бы даже и извинился... :-\ (разумному человеку - достаточно).
В любом случае - не ставил я себе целью "задевать" вас лично, просто, наверное, неудачно сформулировал мысль о том, что не стоит полагаться на порядок исчисления выражений перечисленных через запятую в операторе UPDATE - когда есть четкая конструкция (как раз двойное "=") для выполнения совершенно определенного действия...

Ну вот, а наш с вами "совместный опыт" - подтвердил правильность этой мысли - в разных версиях сервера - одни и те же операторы UPDATE (без двойного "=") - приводят к разным результатам...

P.S.
А "ключевая фраза" в том посте была вовсе не про "в голове", а как раз:
> Не обязательно... но - желательно...

(что ж все впыльчивые-то такие? прям - "на фих никого и не пошлешь"...)
...
Рейтинг: 0 / 0
Сумма с накоплением?
    #32023085
Владимир Смирнов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 qu-qu.
По поводу сервера:
Microsoft SQL Server 7.00 - 7.00.623 (Intel X86)
Nov 27 1998 22:20:07
Copyright (c) 1988-1998 Microsoft Corporation
Desktop Edition on Windows 4.10
А по поводу того, на что стоит и на что не стоит полагаться.
Сообщите, откуда у Вас сведения, что "есть четкая конструкция (как раз двойное "=") ".
Я не встречал такого в BOL. И потому, как человек осторожный, избегаю применять в реальных задачах недокументированные возможности. А двойное присвоение с использованием переменной в запросе, хоть через двойное "=", хоть через "= , =" - это трюкачество. Как в одном тесте по электронике (с молодости запомнил): Вопрос - можно ли включить мс с питанием 5в на 12в? Ответы: 1 - не знаю, 2 - нельзя, 3 - можно, я пробовал, у меня работает.
Так вот: ответ 1 - человек, далёкий от электроники, 2 - инженер, 3 - радиолюбитель. Я предпочитаю инженерный подход, хотя и без экпериментов не обойтись - всё знать нельзя, а делать как-то надо.

Ну а что касается задевать. Я тоже не ставил себе целью "задевать" Вас лично. Просто не люблю, когда кто-то делает поспешные (к тому-же неправильные) выводы и уверенно о них заявляет. Особенно когда эти выводы обо мне.
...
Рейтинг: 0 / 0
Сумма с накоплением?
    #32023121
Фотография SergSuper
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 Владимир Смирнов
насчет двойного "="

сам тоже не верил, пока не посмотрел

\nUPDATE
Changes existing data in a table.

Syntax
UPDATE
{
table_name WITH ( < table_hint_limited > [ ...n ] )
| view_name
| rowset_function_limited
}
SET
{ column_name = { expression | DEFAULT | NULL }
| @variable = expression
| @variable = column = expression } [ ,...n ]

{ { [ FROM { < table_source > } [ ,...n ] ]

[ WHERE
< search_condition > ] }
|
[ WHERE CURRENT OF
{ { [ GLOBAL ] cursor_name } | cursor_variable_name }
] }
[ OPTION ( < query_hint > [ ,...n ] ) ]
...
...
Рейтинг: 0 / 0
Сумма с накоплением?
    #32023180
SergCat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Извините пожалуйста за "ламерство". Но лично мне вы мужики кажетесь такими смешными. Вспомнили "крутую" фишку столетней давности, и давай ее мусолить, хотя от Sergy никакой реакции нет. Конечно фишка очень полезная, а может Sergy как раз и не хочет организовывать поле для хранения суммы с накоплением, или сумма с накоплением нужна в разбивке по разным "ключам" и/или строки достаточно часто меняются местами. В таком случае я вижу одно единственное решение, хотя оно и "напрягает" сервер при каждом запросе (лично я им не пользуюсь):
SELECT ID, Amount, (select SUM(Amount) from Table b where b.ID<=a.ID)
FROM Table a
...
Рейтинг: 0 / 0
Сумма с накоплением?
    #32023219
Владимир Смирнов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Да-а-а. Признаю своё упущение по поводу двойного "=". Был неправ, невнимателен. Спасибо SergSuper.
Согласен с SergCat. Действительно, интереснее случай с вычислением накопительных сумм по группам записей, объединённых общим атрибутом. Но единственное-ли решение - вычисление суммы в подзапросе.
Ведь сумму для текущей записи можно получить как сумма из предыдущей записи + значение. При большом количестве записей может так будет эффективнее?
...
Рейтинг: 0 / 0
14 сообщений из 14, страница 1 из 1
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Сумма с накоплением?
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]