Ilia
|
|
« : 15-12-2004 05:55 » |
|
Здравствуйте, У меня вопрос, чтобы получить сумму по полю, я пишу SELECT SUM(FIELD) FROM TABLE WHERE CONDITION... Чтобы получить содержимое полей, я пишу обыкновенный запрос SELECT FIELD0, FIELD1... FROM TABLE WHERE CONDITION... Возможно ли как-то объединить эти два запроса в единый, чтобы не искать два раза, т.к. условия поиска достаточно громозкие, не хочется их дублировать.
Спасибо.
|
|
|
Записан
|
Кто выпил весь кофе!
|
|
|
PSD
Главный специалист
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
|
|
« Ответ #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
Главный специалист
Offline
Пол:
|
|
« Ответ #4 : 15-12-2004 08:49 » |
|
Ilia, понятно по сути имеем общий случай задачи нумерации строк... В разных бд есть спецефические способы решения задачи в общем случае средствами SQL она не решается. В MS SQL server я получал нумерацию через создание временой таблицы с полем идентии и вставкой туда данных для отчета, и последующим селестом.
Что то похожее можно придумать и для суммы. Если она нужна.
Просто попросить движок пронумеровать строки или пощитать наростающую сумму нельзя так как в нутри движка дб порядок строк произволен, это одна из особеностей реляционных баз данных. Данные упорядываючиваются только пред выдачей пользователю, а в процессе обработки они могут лежать в произвольном порядке и не идентьично предидущему выполнению запроса.
В MS SQL есть механизм последовательной обработки данных называется курсор, используя курсор ты можешь сам перебирать записи и выполнять операции над смежными, но результат работы курсора всеравно нужно сохранять во временную таблицу что бы потом сделать селект на экран.
|
|
|
Записан
|
Да да нет нет все остальное от лукавого.
|
|
|
Ilia
|
|
« Ответ #5 : 15-12-2004 09:04 » |
|
PSD, спасибо я понял, действительно это задача не так проста. Alf, а примерчик такого запроса можешь написать, мне не очень понятна запись SUM0123.
|
|
|
Записан
|
Кто выпил весь кофе!
|
|
|
Alf
Гость
|
|
« Ответ #6 : 15-12-2004 09:55 » |
|
Ilia, не уверен, что ответил именно на заданный вопрос, задача несколько расплывчато сформулирована...
Если нужно найти сумму выбранных полей, то можно просуммировать их в выражении вида FIELD0+FIELD1+..., а конструкция AS позволяет задать имя вычисленному полю (в моем примере - SUM0123, разумеется, можно выбрать любое).
Или нужна сумма не по строкам, а по столбцам?
|
|
|
Записан
|
|
|
|
Ilia
|
|
« Ответ #7 : 15-12-2004 10:48 » |
|
Alf, спасибо. Действительно, посчитать мне надо сумму по столбцам. Но что не менее интересно, сумму по строкам мне тоже надо считать! Так что спасибо за информацию огромное.
|
|
|
Записан
|
Кто выпил весь кофе!
|
|
|
Grinders
Гость
|
|
« Ответ #8 : 15-12-2004 10:59 » |
|
Не проще сделать UNION! 8)
|
|
|
Записан
|
|
|
|
PSD
Главный специалист
Offline
Пол:
|
|
« Ответ #9 : 15-12-2004 11:16 » |
|
Не проще сделать UNION! 8) Он не решит проблему подшета наростающего итога по строкам .... Им можно только присобачить в конц вичесленую сумму
|
|
|
Записан
|
Да да нет нет все остальное от лукавого.
|
|
|
Ilia
|
|
« Ответ #10 : 15-12-2004 11:51 » |
|
В принципе присобачить вычесленную сумму мне сейчас и надо, а примерчик UNION можно?
|
|
|
Записан
|
Кто выпил весь кофе!
|
|
|
PSD
Главный специалист
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
Главный специалист
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
Главный специалист
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 » |
|
...К эконоии ресурсов это не привело но зато избавело от не обходимости воять кусок кода для обединения двух запросов в один отчет. К сожалению, придется ваять другой кусок кода, который должен будет отличать последнюю строку с итогами от остальных. И неизвестно, что хуже. Например, если клиент будет читать данные в цикле через объект DataReader ADO.NET, то нет способа в данный момент узнать, что текущая строка - последняя. Об этом узнаешь только при следующем чтении, когда метод Read() вернет false. Поэтому, если понадобится обрабатывать итоговую строку каким-то особым образом, придется делать буфер для предпросмотра на одну строку, а это тоже не сахар. Или откатывать программу назад на один шаг цикла. Впрочем, теперь черед автора вопроса - выбирать, какое из зол меньше.
|
|
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #17 : 15-12-2004 21:35 » |
|
Насчёт того, что задача нумерации строк в стандартном SQL не решается. Решается, но в частном случае: когда имеются упорядоченные уникальные по полям упорядочивания кортежи.
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Falsehood
Молодой специалист
Offline
Пол:
не может быть
|
|
« Ответ #18 : 16-12-2004 11:22 » |
|
dimka, можно примерчик?
|
|
|
Записан
|
|
|
|
PSD
Главный специалист
Offline
Пол:
|
|
« Ответ #19 : 16-12-2004 12:55 » |
|
dimka, Насчёт того, что задача нумерации строк в стандартном SQL не решается. Решается, но в частном случае: когда имеются упорядоченные уникальные по полям упорядочивания кортежи.
А еще нужно чтобы эти упорядоченые шаг имели 1, те хранить в базе готовые отчеты с нумерацией, которую кстати говоря придется сначало сгенерировать(фактически запись во временную таблицу с полем идентии). В общем случае задача нумерации строк средствами SQL средствами не решается. Alf, Ну тут конечно нужно выбирать изходя из контекста задачи. ИМХО Клиент не должен содержать в себе логики(ну по возможности). Только преобразовывать инфу по заданным правилам и никакой привязки правил к предметной области. Тогда получается вполне живучий клиент который не приходится переписывать по 2 раза в год.
|
|
|
Записан
|
Да да нет нет все остальное от лукавого.
|
|
|
Ilia
|
|
« Ответ #20 : 17-12-2004 04:32 » |
|
Спасибо огромное за инфу. Я попробовал оба варианта и думаю что еще вернусь к этому вопросу позже. Сейчас я сделал подсчет суммы все-таки в клиенте. Простой цикл не сильно нагружает клиента, а нагружать сервер двумя примерно одинаковыми запросами мне не очень хочется. Но я еще буду пробовать и не знаю какой вариант будет окончательным так как сейчас только разрабатываю структуру базы данных и многое в ней и в клиенте еще может поменяться. Еще раз огромное спасибо.
|
|
|
Записан
|
Кто выпил весь кофе!
|
|
|
PSD
Главный специалист
Offline
Пол:
|
|
« Ответ #21 : 17-12-2004 05:58 » |
|
Ilia, слушай если у тебя подсчет суммы в ручную не сильно нагружает клиента то стопудово он и сервер не нагрузит(он то по логике должен быть на мощнее клиента) ... и кстати есть несколько способов сильно облегчить жизнь сервера в случае когда проводится ряд последовательных вычислений на одном наборе данных. У меня такая ситуация 200 приборов с каждого архивы суточные и часовые это сейчас база за несколько лет порятка 2х милионов записей и все это безобразие в одной таблице. Когда я провожу анализ у меня в нем участвует сравнительно небольшой объем данных 4-5 приборов при глубине в среднем до месяца. Все начинает значительно быстрее вертется если перед всеми выборками скопировать набор данных во временную таблицу ... даже без оптимизации условий поиска такой переход сократил вчемя выполнения последующих запросов на 80%
|
|
|
Записан
|
Да да нет нет все остальное от лукавого.
|
|
|
Ilia
|
|
« Ответ #22 : 17-12-2004 06:33 » |
|
Да, я тоже думал над временными таблицами. Хотя у меня база гораздо скромнее - всего порядка 10000 записей. Временную таблицу я думаю завести для отбора записей. У меня пользователь задает условия, сервер возвращает найденные записи, затем пользователь выбирает некоторые из записей (какие ему подходят) - первичные ключи отобранных записей у меня хранятся в стеке у клиента, затем пользователь повторно ищет по другим своим условиям (сделать поиск за один раз невозможно т.к. таков алгоритм работы пользователя) и опять выбирает нужные записи они тоже добавляются в стек. И так несколько раз, пока user не испробует все свои идеи. Потом все это отобранное безобразие уже идет на распечатку. Причем каждую запись приходится заново запрашивать с сервера с полным набором необходимых для распечатки полей используя PK из стека. Вот такой не оптимальный алгоритм в данный момент используется. Я думаю вместо стека клиента писать данные во временную таблицу с указанием имени пользователя, тем более, что пользователь еще иногда хочет перед распечаткой данные заново сортировать.
|
|
|
Записан
|
Кто выпил весь кофе!
|
|
|
Dimka
Деятель
Команда клуба
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
Главный специалист
Offline
Пол:
|
|
« Ответ #24 : 20-12-2004 06:55 » |
|
dimka, хорошая идея с нумерацией запомню.... Я думаю вместо стека клиента писать данные во временную таблицу с указанием имени пользователя, тем более, что пользователь еще иногда хочет перед распечаткой данные заново сортировать.
Ilia, у MS SQL Server есть для такой задачи специальный механизм временных таблиц они создаются с # или ## в одном случае получаем таблицу доступную всем в другом получаем персональную таблицу для каждого пользователя(насамом деле логина). Очень удобно и что самое приятное система дропит их самостоятельно при закрытии транзакции или соединения. Что несколько снижает количество запросов на еденицу данных.
|
|
|
Записан
|
Да да нет нет все остальное от лукавого.
|
|
|
Falsehood
Молодой специалист
Offline
Пол:
не может быть
|
|
« Ответ #25 : 20-12-2004 13:39 » |
|
dimka, хороший пособ, но в FoxPro, например, не поддерживаются подзапросы в качестве выражений для полей в запросах
|
|
|
Записан
|
|
|
|
Ilia
|
|
« Ответ #26 : 22-12-2004 04:51 » |
|
PSD, Alf, dimka Спасибо еще раз за советы, полезная информация.
|
|
|
Записан
|
Кто выпил весь кофе!
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #27 : 22-12-2004 07:40 » |
|
Falsehood Ещё раз повторяю, стандарт SQL89 и большое число всяких СУБД, его поддерживающих, так делать не умеют. Поэтому, естественно. Думаю, и в BDE на Paradox-табличках такое не получится сделать. Я специально не интересовался, какие СУБД умеют, а какие нет. Самое простое - посмотреть в документации базовый стандарт для каждого конкретного случая.
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
|