Этот баннер — требование Роскомнадзора для исполнения 152 ФЗ.
«На сайте осуществляется обработка файлов cookie, необходимых для работы сайта, а также для анализа использования сайта и улучшения предоставляемых сервисов с использованием метрической программы Яндекс.Метрика. Продолжая использовать сайт, вы даёте согласие с использованием данных технологий».
Политика конфиденциальности
|
|
|
Сумма с накоплением?
|
|||
|---|---|---|---|
|
#18+
Добрый день всем! Когда-то видел решение этой задачи, но поиск нечего не дал. Может кто знает как грамотно решить задачу сумма с накоплением, т.е. Есть таблица в которой столбец А содержит числа. Нужно сформировать столбец B, в котором каждая строчка будет содержать сумму всех предыдущих по столбцу А. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.02.2002, 08:05 |
|
||
|
Сумма с накоплением?
|
|||
|---|---|---|---|
|
#18+
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 ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.02.2002, 08:27 |
|
||
|
Сумма с накоплением?
|
|||
|---|---|---|---|
|
#18+
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 по дате и все просуммируется правильно). Удачи!! ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.02.2002, 09:13 |
|
||
|
Сумма с накоплением?
|
|||
|---|---|---|---|
|
#18+
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, но все же. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.02.2002, 09:50 |
|
||
|
Сумма с накоплением?
|
|||
|---|---|---|---|
|
#18+
2 Glory Спасибо за поправку... (в пылу жажды откровений - совсем позабыл, что самое главное в сумме все же - value ) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.02.2002, 10:37 |
|
||
|
Сумма с накоплением?
|
|||
|---|---|---|---|
|
#18+
Использовать "трюк" с двойным "=" совсем необязательно. Можно так: 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 --сумма передыдущих строк и текущей ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.02.2002, 11:43 |
|
||
|
Сумма с накоплением?
|
|||
|---|---|---|---|
|
#18+
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 (ответом - не мучайтесь... никакие... можете потом сами - на сервере проверить). ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.02.2002, 15:19 |
|
||
|
Сумма с накоплением?
|
|||
|---|---|---|---|
|
#18+
2 Владимир Смирнов М-да... Вынужден перед вами извиниться, т.к. сам поступил точно по "критикуемой" схеме... (проверил только 3 запроса, а 4-й дописал в спешке уже в постинге, потому и "set @running_sum = 0" забыл перед ним воткнуть...) На самом деле - 3-й и 4-й сделают одинаковые действия (и одинаково - неправильные), а 1-й и 2-й - таки разные... (и как раз - нужные) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.02.2002, 15:38 |
|
||
|
Сумма с накоплением?
|
|||
|---|---|---|---|
|
#18+
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 Есть ещё вопросы? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.02.2002, 07:34 |
|
||
|
Сумма с накоплением?
|
|||
|---|---|---|---|
|
#18+
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. А "ключевая фраза" в том посте была вовсе не про "в голове", а как раз: > Не обязательно... но - желательно... (что ж все впыльчивые-то такие? прям - "на фих никого и не пошлешь"...) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.02.2002, 08:56 |
|
||
|
Сумма с накоплением?
|
|||
|---|---|---|---|
|
#18+
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 - радиолюбитель. Я предпочитаю инженерный подход, хотя и без экпериментов не обойтись - всё знать нельзя, а делать как-то надо. Ну а что касается задевать. Я тоже не ставил себе целью "задевать" Вас лично. Просто не люблю, когда кто-то делает поспешные (к тому-же неправильные) выводы и уверенно о них заявляет. Особенно когда эти выводы обо мне. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.02.2002, 10:02 |
|
||
|
Сумма с накоплением?
|
|||
|---|---|---|---|
|
#18+
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 ] ) ] ... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.02.2002, 11:51 |
|
||
|
Сумма с накоплением?
|
|||
|---|---|---|---|
|
#18+
Извините пожалуйста за "ламерство". Но лично мне вы мужики кажетесь такими смешными. Вспомнили "крутую" фишку столетней давности, и давай ее мусолить, хотя от Sergy никакой реакции нет. Конечно фишка очень полезная, а может Sergy как раз и не хочет организовывать поле для хранения суммы с накоплением, или сумма с накоплением нужна в разбивке по разным "ключам" и/или строки достаточно часто меняются местами. В таком случае я вижу одно единственное решение, хотя оно и "напрягает" сервер при каждом запросе (лично я им не пользуюсь): SELECT ID, Amount, (select SUM(Amount) from Table b where b.ID<=a.ID) FROM Table a ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 16.02.2002, 20:14 |
|
||
|
Сумма с накоплением?
|
|||
|---|---|---|---|
|
#18+
Да-а-а. Признаю своё упущение по поводу двойного "=". Был неправ, невнимателен. Спасибо SergSuper. Согласен с SergCat. Действительно, интереснее случай с вычислением накопительных сумм по группам записей, объединённых общим атрибутом. Но единственное-ли решение - вычисление суммы в подзапросе. Ведь сумму для текущей записи можно получить как сумма из предыдущей записи + значение. При большом количестве записей может так будет эффективнее? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.02.2002, 06:28 |
|
||
|
|

start [/forum/topic.php?fid=46&msg=32023121&tid=1823875]: |
0ms |
get settings: |
11ms |
get forum list: |
20ms |
check forum access: |
3ms |
check topic access: |
3ms |
track hit: |
167ms |
get topic data: |
9ms |
get forum data: |
2ms |
get page messages: |
52ms |
get tp. blocked users: |
1ms |
| others: | 267ms |
| total: | 535ms |

| 0 / 0 |
