Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Простой вопрос сумма по полю SQL  (Прочитано 61237 раз)
0 Пользователей и 3 Гостей смотрят эту тему.
Ilia
Помогающий

ru
Offline Offline
Пол: Мужской

« : 15-12-2004 05:55 » new

Здравствуйте,
У меня вопрос, чтобы получить сумму по полю, я пишу SELECT SUM(FIELD) FROM TABLE WHERE CONDITION...
Чтобы получить содержимое полей, я пишу обыкновенный запрос SELECT FIELD0, FIELD1... FROM TABLE WHERE CONDITION...
Возможно ли как-то объединить эти два запроса в единый, чтобы не искать два раза, т.к. условия поиска достаточно громозкие, не хочется их дублировать.

Спасибо.
Записан

Кто выпил весь кофе!
PSD
Главный специалист

ru
Offline Offline
Пол: Мужской

« Ответ #1 : 15-12-2004 06:07 » 

В смысле обеденить?
Sum это агрегатная функция котрая всегда возвращает одну запись.
Можно сделать так
select f1,f2,f3, sum(f4) from table where condition
group by f1,f2,f3
в этом случае сумма будет считатся для груп с одинаковыми f1,f2,f3
Записан

Да да нет нет все остальное от лукавого.
Ilia
Помогающий

ru
Offline Offline
Пол: Мужской

« Ответ #2 : 15-12-2004 06:32 » 

PSD, Спасибо но у меня несколько другая задача.
Мне нужно вначале получить все записи из таблицы согласно условию. Затем мне нужно посчитать сумму по числовому полю в найденных записях.
Это все прекрасно работает если выполнять два запроса по условию, но не хочется нагружать сервер двумя запросами.  
Т.е. я хочу создать запрос в котором столбец SUM должен содержать накопительную сумму (первая запись - только свое значение, вторая запись = первая + вторая и т.д., последняя запись должна быть сумма всех записей по считаемому полю).
f1, f2, f3 у меня всегда разные т.к. f1 вообще первичный ключ.
Записан

Кто выпил весь кофе!
Alf
Гость
« Ответ #3 : 15-12-2004 08:20 » 

Похоже, что поможет запрос вида

Код:
SELECT FIELD0, FIELD1,...,  FIELD0+FIELD1+... AS SUM0123 
FROM TABLE
WHERE CONDITION
Записан
PSD
Главный специалист

ru
Offline Offline
Пол: Мужской

« Ответ #4 : 15-12-2004 08:49 » 

Ilia, понятно по сути имеем общий случай задачи нумерации строк...
В разных бд есть спецефические способы решения задачи  в общем случае средствами SQL она не решается.
 В MS SQL server  я получал нумерацию через создание временой таблицы с полем идентии  и вставкой туда данных для отчета, и последующим селестом.

Что то похожее можно придумать и для суммы. Если она нужна.

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

В MS SQL есть механизм последовательной обработки данных называется курсор, используя курсор ты можешь сам перебирать записи и выполнять операции над смежными, но результат работы курсора всеравно нужно сохранять во временную таблицу что бы потом сделать селект на экран.
Записан

Да да нет нет все остальное от лукавого.
Ilia
Помогающий

ru
Offline Offline
Пол: Мужской

« Ответ #5 : 15-12-2004 09:04 » 

PSD, спасибо я понял, действительно это задача не так проста.
Alf,  а примерчик такого запроса можешь написать, мне не очень понятна запись SUM0123.
Записан

Кто выпил весь кофе!
Alf
Гость
« Ответ #6 : 15-12-2004 09:55 » 

Ilia, не уверен, что ответил именно на заданный вопрос, задача несколько расплывчато сформулирована...

Если нужно найти сумму выбранных полей, то можно просуммировать их в выражении вида FIELD0+FIELD1+..., а конструкция AS позволяет задать имя вычисленному полю (в моем примере - SUM0123, разумеется, можно выбрать любое).

Или нужна сумма не по строкам, а по столбцам?
Записан
Ilia
Помогающий

ru
Offline Offline
Пол: Мужской

« Ответ #7 : 15-12-2004 10:48 » 

Alf, спасибо. Действительно, посчитать мне надо сумму по столбцам.
Но что не менее интересно, сумму по строкам мне тоже надо считать!
Так что спасибо за информацию огромное.
Записан

Кто выпил весь кофе!
Grinders
Гость
« Ответ #8 : 15-12-2004 10:59 » 

Не проще сделать UNION! 8)
Записан
PSD
Главный специалист

ru
Offline Offline
Пол: Мужской

« Ответ #9 : 15-12-2004 11:16 » 

Цитата: Grinders
Не проще сделать UNION! 8)

Он не решит проблему подшета наростающего итога по строкам ....
Им можно только присобачить в конц вичесленую сумму
Записан

Да да нет нет все остальное от лукавого.
Ilia
Помогающий

ru
Offline Offline
Пол: Мужской

« Ответ #10 : 15-12-2004 11:51 » 

В принципе присобачить вычесленную сумму мне сейчас и надо, а примерчик UNION можно?
Записан

Кто выпил весь кофе!
PSD
Главный специалист

ru
Offline Offline
Пол: Мужской

« Ответ #11 : 15-12-2004 12:26 » 

Select f1,f2,f3,f4 from table where ....
union all
Select null,null,null ,sum(f4) from table where ....

Главное чтобы число полей в первом и последующем селектах совпадало.
Записан

Да да нет нет все остальное от лукавого.
Alf
Гость
« Ответ #12 : 15-12-2004 12:36 » 

Ilia, скорее всего, придется делать два запроса.

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

Во-вторых, даже если бы удалось одолеть пункт "во-первых", то каким образом представить конечный результат? Первый SELECT выберет набор кортежей, и как прилепить к ним суммарные значения? Добавить строку "итого" через UNION? На мой взгляд, авантюрное решение, т.к. в общем случае порядок кортежей в отношении не определен, и после манипуляций итоговая строка может оказаться где-нибудь в середине.

Лучше оставить два запроса, т.к. смешивание их в одном создаст больше проблем, чем решит. А еще лучше - посчитать суммы в самой программе, которая выполняет первый запрос. Иначе если между первым и вторым запросами в базу добавится строка, возникнет весьма щекотливая ситуация, когда итоговое значение не равно сумме. Или придется блокировать таблицу на время подсчета, чтобы избежать этого.
Записан
PSD
Главный специалист

ru
Offline Offline
Пол: Мужской

« Ответ #13 : 15-12-2004 12:46 » 

Alf,
Цитата

Во-вторых, даже если бы удалось одолеть пункт "во-первых", то каким образом представить конечный результат? Первый SELECT выберет набор кортежей, и как прилепить к ним суммарные значения? Добавить строку "итого" через UNION? На мой взгляд, авантюрное решение, т.к. в общем случае порядок кортежей в отношении не определен, и после манипуляций итоговая строка может оказаться где-нибудь в середине.

Это очень просто решается

select 1 as levels ,.... from table ....
unuon all
select 2 as levels ,.... from table ....
order by levels

есть еще несколько варинтов горантирующих правельный порядок блоков обедененых по union
Записан

Да да нет нет все остальное от лукавого.
Alf
Гость
« Ответ #14 : 15-12-2004 13:00 » 

PSD, правильно, но это уже другой формат таблицы... Добавилось лишнее поле, и неочевидно, что оно не помешает где-нибудь в другой части программы. (Запросов SELECT при этом как было два, так и осталось, ничего не упростили). Да и сама программа теперь должна различать два вида записей по полю levels. Хоть и невеликое усложнение, но весьма искусственное - сначала замешать в кучу, потом разделять.
Записан
PSD
Главный специалист

ru
Offline Offline
Пол: Мужской

« Ответ #15 : 15-12-2004 13:12 » 

Alf, это самый простой и наглядный варинт ...
вот еще (незнаю как в других БД в ms SQL я делал так )

select f1,f2,f3,f4 from
(
select f1,f2,f3,f4, 1 as levels
union all
select null,null,null,f4, 2 as levels
) td
order by levels

К эконоии ресурсов это не привело но зато избавело от не обходимости  воять  кусок кода для обединения двух запросов в один отчет.

ИМХО все что можно должен делать сервер так как он один и править его проще чем клинета.
Записан

Да да нет нет все остальное от лукавого.
Alf
Гость
« Ответ #16 : 15-12-2004 13:32 » 

Цитата: PSD
...К эконоии ресурсов это не привело но зато избавело от не обходимости  воять  кусок кода для обединения двух запросов в один отчет.

К сожалению, придется ваять другой кусок кода, который должен будет отличать последнюю строку с итогами от остальных. И неизвестно, что хуже.

Например, если клиент будет читать данные в цикле через объект DataReader ADO.NET, то нет способа в данный момент узнать, что текущая строка - последняя. Об этом узнаешь только при следующем чтении, когда метод Read() вернет false. Поэтому, если понадобится обрабатывать итоговую строку каким-то особым образом, придется делать буфер для предпросмотра на одну строку, а это тоже не сахар. Или откатывать программу назад на один шаг цикла.

Впрочем, теперь черед автора вопроса - выбирать, какое из зол меньше.
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #17 : 15-12-2004 21:35 » 

Насчёт того, что задача нумерации строк в стандартном SQL не решается. Решается, но в частном случае: когда имеются упорядоченные уникальные по полям упорядочивания кортежи.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Falsehood
Молодой специалист

ru
Offline Offline
Пол: Женский
не может быть


« Ответ #18 : 16-12-2004 11:22 » 

dimka, можно примерчик?
Записан

Славная трава...
PSD
Главный специалист

ru
Offline Offline
Пол: Мужской

« Ответ #19 : 16-12-2004 12:55 » 

dimka,
Цитата

Насчёт того, что задача нумерации строк в стандартном SQL не решается. Решается, но в частном случае: когда имеются упорядоченные уникальные по полям упорядочивания кортежи.

А еще нужно чтобы эти упорядоченые шаг имели 1, те  хранить  в базе готовые отчеты с нумерацией, которую кстати говоря придется сначало сгенерировать(фактически запись во временную таблицу с полем идентии).
 В общем случае задача нумерации строк средствами SQL средствами не решается.
Alf, Ну тут конечно нужно выбирать изходя из контекста задачи.
ИМХО Клиент не должен содержать в себе логики(ну по возможности). Только преобразовывать инфу по заданным правилам и никакой привязки правил к предметной области. Тогда получается вполне живучий клиент который не приходится переписывать по 2 раза в год.
Записан

Да да нет нет все остальное от лукавого.
Ilia
Помогающий

ru
Offline Offline
Пол: Мужской

« Ответ #20 : 17-12-2004 04:32 » 

Спасибо огромное за инфу. Я попробовал оба варианта и думаю что еще вернусь к этому вопросу позже. Сейчас я сделал подсчет суммы все-таки в клиенте. Простой цикл не сильно нагружает клиента, а нагружать сервер двумя примерно одинаковыми запросами мне не очень хочется. Но я еще буду пробовать и не знаю какой вариант будет окончательным так как сейчас только разрабатываю структуру базы данных и многое в ней и в клиенте еще может поменяться.
Еще раз огромное спасибо.
Записан

Кто выпил весь кофе!
PSD
Главный специалист

ru
Offline Offline
Пол: Мужской

« Ответ #21 : 17-12-2004 05:58 » 

Ilia, слушай если у тебя подсчет суммы в ручную не сильно нагружает клиента то стопудово он и сервер не нагрузит(он то по логике должен быть на мощнее клиента) ... и кстати  есть несколько способов сильно облегчить жизнь сервера в случае когда проводится ряд последовательных вычислений на одном наборе данных.

У меня такая ситуация 200 приборов с каждого архивы суточные и часовые это сейчас база за несколько лет порятка 2х милионов записей и все это безобразие в одной таблице.  Когда я провожу анализ у меня в нем участвует сравнительно небольшой объем данных 4-5 приборов при глубине  в среднем до месяца. Все начинает значительно быстрее вертется если перед всеми выборками скопировать набор данных во временную таблицу  ... даже без оптимизации условий поиска такой переход сократил вчемя выполнения последующих запросов  на 80%   Улыбаюсь
Записан

Да да нет нет все остальное от лукавого.
Ilia
Помогающий

ru
Offline Offline
Пол: Мужской

« Ответ #22 : 17-12-2004 06:33 » 

Да, я тоже думал над временными таблицами. Хотя у меня база гораздо скромнее - всего порядка 10000 записей. Временную таблицу я думаю завести для отбора записей. У меня пользователь задает условия, сервер возвращает найденные записи, затем пользователь выбирает некоторые из записей (какие ему подходят) - первичные ключи отобранных записей у меня хранятся в стеке у клиента, затем пользователь повторно ищет по другим своим условиям (сделать поиск за один раз невозможно т.к. таков алгоритм работы пользователя) и опять выбирает нужные записи они тоже добавляются в стек. И так несколько раз, пока user не испробует все свои идеи.
Потом все это отобранное безобразие уже идет на распечатку. Причем каждую запись приходится заново запрашивать с сервера с полным набором необходимых для распечатки полей используя PK из стека. Вот такой не оптимальный алгоритм в данный момент используется.
Я думаю вместо стека клиента писать данные во временную таблицу с указанием имени пользователя, тем более, что пользователь еще иногда хочет перед распечаткой данные заново сортировать.
Записан

Кто выпил весь кофе!
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #23 : 17-12-2004 11:07 » 

PSD, Falsehood, пожалста
Код:

select
  CompanyName,
  ContactName,
  )select count)*:
   from Customers c2
   where c2.CustomerID <= c1.CustomerID: RowNo
from Customers c1

на учебной базе Northwind (в Microsoft'овских СУБД). Нумерация пойдёт в алфавитном порядке ID.

Единственно, что в SQL89 гарантированно нельзя подзапрос как поле использовать, но вот в SQL92, а в более поздних стандартах тем более, в этом нет ничего преступного.

PSD, по расчётам через временные таблицы - логично Улыбаюсь, ему ж не надо уже 2 млн. записей для каждой операции использовать Улыбаюсь
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
PSD
Главный специалист

ru
Offline Offline
Пол: Мужской

« Ответ #24 : 20-12-2004 06:55 » 

dimka, хорошая идея с нумерацией запомню....  Улыбаюсь
Цитата

Я думаю вместо стека клиента писать данные во временную таблицу с указанием имени пользователя, тем более, что пользователь еще иногда хочет перед распечаткой данные заново сортировать.


Ilia, у MS SQL Server есть для такой задачи специальный механизм временных таблиц
они создаются с # или ## в одном случае получаем таблицу доступную всем в другом получаем персональную таблицу для каждого пользователя(насамом деле логина). Очень удобно и что самое приятное система дропит их самостоятельно при закрытии транзакции или соединения. Что несколько снижает количество запросов на еденицу данных.
Записан

Да да нет нет все остальное от лукавого.
Falsehood
Молодой специалист

ru
Offline Offline
Пол: Женский
не может быть


« Ответ #25 : 20-12-2004 13:39 » 

dimka, хороший пособ, но в FoxPro, например, не поддерживаются подзапросы в качестве выражений для полей в запросах Жаль
Записан

Славная трава...
Ilia
Помогающий

ru
Offline Offline
Пол: Мужской

« Ответ #26 : 22-12-2004 04:51 » 

PSD, Alf, dimka Спасибо еще раз за советы, полезная информация.
Записан

Кто выпил весь кофе!
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #27 : 22-12-2004 07:40 » 

Falsehood
Ещё раз повторяю, стандарт SQL89 и большое число всяких СУБД, его поддерживающих, так делать не умеют. Поэтому, естественно. Думаю, и в BDE на Paradox-табличках такое не получится сделать. Я специально не интересовался, какие СУБД умеют, а какие нет. Самое простое - посмотреть в документации базовый стандарт для каждого конкретного случая.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines