|
|
Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
|
Опции темы | Поиск в этой теме | Опции просмотра |
#1
|
||||
|
||||
Сумма по колонке (с добавлением)
Задачка такая:
пользователь должен добавлять в таблицу элементы: по принципу заполняется поле А заполняется поле Б автоподсчёт поле С = А*Б; Здесь первый вопрос. Если полю С выдать AutoCalc, и в onFieldCalc обрабатывать его подсчёт, то почему-то это значение не сохраняется в Таблицу. Что я делаю не так? Далее с каждым новым элементом общая сумма по колонке С должна отображаться на форме. Вторая часть реализована следующим образом: Код:
var TotalPrice: real; begin with fMain.Items do begin Post; TotalPrice := 0; First; while not Eof do begin TotalPrice := TotalPrice + FieldByName('Price').AsFloat; Next; end; maxPrice.Text := FormatFloat('0.00', TotalPrice); maxLoan.Text := FormatFloat('0.00', TotalPrice * 0.76); end; Была мысли уйти от ADOTable и воспользоваться ADOQuery и запросом (SUM), но как-то весь проект в таблицах.) Это скорее эстетика. Может стоит отказаться от таблиц? Последний раз редактировалось Uniq!, 27.09.2013 в 12:28. |
#2
|
||||
|
||||
Конечно отказывайся, пока не стало еще хуже
Если таблицы есть и их много и не охота переделывать, то сделай симбиоз с квериками Бд - доска, таблицы - топор, кверики - электролобзик)) Я за здоровый экстрим! Спасибо за "спасибо") |
Этот пользователь сказал Спасибо Mrak за это полезное сообщение: | ||
Uniq! (27.09.2013)
|
#3
|
||||
|
||||
Раз тут начался поиск серебряной пули, считаю нужным отписаться для контекста.
На самом деле задача подсчета итогов прямо в процессе ввода нетривиальна для DB-компонентов и является частным проявлением проблемы размазывания логики между клиентом и сервером. Подсчет суммы агрегатной функцией sum на сервере -- это одно, а подсчет и функцией на сервере, и еще какими-то костылями на клиенте во время ввода -- это другое. Без костылей, к сожалению, не получается, поскольку большинство DB-компонентов не умеют делать это штатно. ADO в их числе, но в других компонентах я что-то тоже такого не припомню. Поэтому, если задача именно в подсчете на лету, любое решение будет вынужденным костылем, называемым заграничным словом workaround, зато при работе с ним будет греть мысль, что это не просто мелкая проблема, а частное проявление чего-то большего, что до сих пор не решено в компьютерной науке. |
Этот пользователь сказал Спасибо Freeman за это полезное сообщение: | ||
Uniq! (27.09.2013)
|
#4
|
||||
|
||||
Все несколько не так.
Если вы хотите только видеть результаты в таблице то вам нужно использовать calcfield. Но! Имейте ввиду что это по сути виртуальное поле и живет оно только на экране. Обратится извне к нему не выйдет ибо его в таблице физически не существует. Более приятный и удобный способ - это сделать запрос с вычислением. Вот тогда уже можно к такому полю обратится извне. Но и тут без подводных камней не обойдется если вам нужен подсчет при вводе. Жизнь такова какова она есть и больше никакова. Помогаю за спасибо. |
Этот пользователь сказал Спасибо Страдалецъ за это полезное сообщение: | ||
Uniq! (27.09.2013)
|
#5
|
||||
|
||||
Ребят, вот wiki:fkInternalCalc.
Я так понимаю, это мой ключ от замка к первой части задачи. Только вот справиться с ним не могу. 1) Двойной клик на "открытом" TADOTable (т.е. DataSet заполнен) 2) Добавляю все колонки 3) Выставляю нужным колонкам в свойствах fkInternalCalc 4) Обрабатываю в OnCalcFields подсчёт этой колонки: Код:
procedure TfMain.ItemsCalcFields(DataSet: TDataSet); begin DataSet.FieldByName('MetallWeight').AsFloat := DataSet.FieldByName('Weight') .AsFloat - DataSet.FieldByName('InsertWeight').AsFloat; DataSet.FieldByName('Price').AsFloat := DataSet.FieldByName('MetallWeight') .AsFloat * DataSet.FieldByName('Pricep1g').AsFloat; end; С TADOQuery не работал. Пока попробую вникнуть. Последний раз редактировалось Uniq!, 27.09.2013 в 14:06. |
Этот пользователь сказал Спасибо Uniq! за это полезное сообщение: | ||
Freeman (27.09.2013)
|
#6
|
||||
|
||||
Цитата:
Как понимаю, этот вид поля предназначен для вычисляемых полей с кэшируемыми значениями, которые и хранятся в наборе данных. Не поленился и посмотрел в исходниках, как это реализовано. Похоже, что это базовая функциональность, реализованная в модуле DB и унаследованная всеми наследниками TDataSet. Стало быть, и в ADO должно быть. Как можно догадаться, я сам fkInternalCalc ни разу не пользовал... Могу предположить, что значения этих полей нужно изменять вместе с изменением основных полей, раз они физически хранятся в наборе данных. Если сработает, мне придется посыпать голову пеплом взять назад свои слова об отсутствии в DB-компонентах возможности подсчета на лету. |
#7
|
||||
|
||||
У меня походу разбирательств с циклом всплыло такое решение:
Добавить ADOCommand c текстом: Код:
select SUM(Price) from litems where IDTicket = null Код:
var TotalPrice: real; begin with fMain.Items do begin FieldByName('MetallWeight').AsFloat := FieldByName('Weight').AsFloat - FieldByName('InsertWeight').AsFloat; FieldByName('Price').AsFloat := FieldByName('MetallWeight').AsFloat * FieldByName('Pricep1g').AsFloat; Post; // здесь ещё BeforePost обрабатывает качество введённой инфы // я так подумал, что качество Weight и InsertWeight проверять не надо, ибо сами визуальные DBEdit это делаю сами, опираясь на тип поля end; TotalPrice := VarAsType((fMain.cmdSumItem.Execute).Fields[0].Value, varDouble); maxPrice.Text := FormatFloat('0.00', TotalPrice); maxLoan.Text := FormatFloat('0.00', TotalPrice * 0.76); Я пока отказался от подсчёт "налету" (временно), поэтому пересчёт находится "здесь". Проблема нарисовалась: ADOCOmmand возвращает NULL. Из-за того, что Items находятся в режиме ltBatchOptimistic, и ADOCoomand не видит ещё не отправленного на Сервер изменений? Или where IDTicket = null имеет другой синтаксис? вот это не нравится = null. В классическом SQL where IDTicket IS Null Пока не работает не первый вариант = null, не второй is null. Нужны параметры? Последний раз редактировалось Uniq!, 27.09.2013 в 15:47. |
#8
|
|||
|
|||
Я бы посоветовал бы не напрягаться.
1. Для подсчета произведения можно спокойно использовать вычисляемое поле (calcField), т.к. это значение ВСЕГДА можно вычислить, если оно понадобится (вспоминаем принципы проектирования БД - не надо хранить в базе то, что всегда можно вычислить). 2. Для подсчета суммы "на лету" можно либо воспользоваться готовым гридом, который это умеет (например, от DevExpress, вроде EhLib'овсеий тоже умеет), либо написать свой код (тут фокус в том, что надо запомнить текущую позицию курсора, отключить визуальную часть компонентов /там метод спец. есть/, пробежаться по датасету вычисляя сумму, потом вернуться на запомненную строчку и обратно подключить визуальную часть. Это будет работать быстро даже для большого кол-ва записей). |
#9
|
||||
|
||||
Цитата:
Я за здоровый экстрим! Спасибо за "спасибо") Последний раз редактировалось Mrak, 27.09.2013 в 16:41. |