Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > Все о Delphi > Базы данных
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 27.09.2013, 12:14
Аватар для Uniq!
Uniq! Uniq! вне форума
Местный
 
Регистрация: 29.09.2010
Сообщения: 539
Версия Delphi: Delphi XE3
Репутация: 374
По умолчанию Сумма по колонке (с добавлением)

Задачка такая:
пользователь должен добавлять в таблицу элементы: по принципу
заполняется поле А
заполняется поле Б
автоподсчёт поле С = А*Б;

Здесь первый вопрос. Если полю С выдать 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;
Получается, что каждый раз программа пересчитывает предыдущие элементы. А если их будет 100, и добавляться 101 ... а если 1000.

Была мысли уйти от ADOTable и воспользоваться ADOQuery и запросом (SUM), но как-то весь проект в таблицах.) Это скорее эстетика. Может стоит отказаться от таблиц?

Последний раз редактировалось Uniq!, 27.09.2013 в 12:28.
Ответить с цитированием
  #2  
Старый 27.09.2013, 12:46
Аватар для Mrak
Mrak Mrak вне форума
Местный
 
Регистрация: 26.01.2013
Адрес: МО
Сообщения: 438
Версия Delphi: XE2
Репутация: 17
По умолчанию

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

Бд - доска, таблицы - топор, кверики - электролобзик))
__________________
Я за здоровый экстрим!
Спасибо за "спасибо")
Ответить с цитированием
Этот пользователь сказал Спасибо Mrak за это полезное сообщение:
Uniq! (27.09.2013)
  #3  
Старый 27.09.2013, 13:12
Аватар для Freeman
Freeman Freeman вне форума
Местный
 
Регистрация: 05.10.2012
Адрес: Санкт-Петербург
Сообщения: 576
Версия Delphi: 6
Репутация: выкл
По умолчанию

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

На самом деле задача подсчета итогов прямо в процессе ввода нетривиальна для DB-компонентов и является частным проявлением проблемы размазывания логики между клиентом и сервером. Подсчет суммы агрегатной функцией sum на сервере -- это одно, а подсчет и функцией на сервере, и еще какими-то костылями на клиенте во время ввода -- это другое. Без костылей, к сожалению, не получается, поскольку большинство DB-компонентов не умеют делать это штатно. ADO в их числе, но в других компонентах я что-то тоже такого не припомню.

Поэтому, если задача именно в подсчете на лету, любое решение будет вынужденным костылем, называемым заграничным словом workaround, зато при работе с ним будет греть мысль, что это не просто мелкая проблема, а частное проявление чего-то большего, что до сих пор не решено в компьютерной науке.
Ответить с цитированием
Этот пользователь сказал Спасибо Freeman за это полезное сообщение:
Uniq! (27.09.2013)
  #4  
Старый 27.09.2013, 13:27
Аватар для Страдалецъ
Страдалецъ Страдалецъ вне форума
Гуру
 
Регистрация: 09.03.2009
Адрес: На курорте, из окна вижу теплое Баренцево море. Бррр.
Сообщения: 4,721
Репутация: 52347
По умолчанию

Все несколько не так.
Если вы хотите только видеть результаты в таблице то вам нужно использовать calcfield. Но! Имейте ввиду что это по сути виртуальное поле и живет оно только на экране. Обратится извне к нему не выйдет ибо его в таблице физически не существует. Более приятный и удобный способ - это сделать запрос с вычислением. Вот тогда уже можно к такому полю обратится извне. Но и тут без подводных камней не обойдется если вам нужен подсчет при вводе.
__________________
Жизнь такова какова она есть и больше никакова.
Помогаю за спасибо.
Ответить с цитированием
Этот пользователь сказал Спасибо Страдалецъ за это полезное сообщение:
Uniq! (27.09.2013)
  #5  
Старый 27.09.2013, 13:57
Аватар для Uniq!
Uniq! Uniq! вне форума
Местный
 
Регистрация: 29.09.2010
Сообщения: 539
Версия Delphi: Delphi XE3
Репутация: 374
По умолчанию

Ребят, вот 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;
Обычно, при вводе в связанные с DataSet'ом TDBEdit'ы, изменения сразу отображаются в DBGrid. А вот с fkInternalCalc ничего не происходит.

С TADOQuery не работал. Пока попробую вникнуть.

Последний раз редактировалось Uniq!, 27.09.2013 в 14:06.
Ответить с цитированием
Этот пользователь сказал Спасибо Uniq! за это полезное сообщение:
Freeman (27.09.2013)
  #6  
Старый 27.09.2013, 15:11
Аватар для Freeman
Freeman Freeman вне форума
Местный
 
Регистрация: 05.10.2012
Адрес: Санкт-Петербург
Сообщения: 576
Версия Delphi: 6
Репутация: выкл
По умолчанию

Цитата:
Сообщение от Uniq!
А вот с fkInternalCalc ничего не происходит.
Во, век живи, век учись. Раньше думал, что fkInternalCalc -- для совместимости с древними версиями VCL, гвоздями прибитыми к BDE. Ан нет.

Как понимаю, этот вид поля предназначен для вычисляемых полей с кэшируемыми значениями, которые и хранятся в наборе данных. Не поленился и посмотрел в исходниках, как это реализовано. Похоже, что это базовая функциональность, реализованная в модуле DB и унаследованная всеми наследниками TDataSet. Стало быть, и в ADO должно быть.

Как можно догадаться, я сам fkInternalCalc ни разу не пользовал... Могу предположить, что значения этих полей нужно изменять вместе с изменением основных полей, раз они физически хранятся в наборе данных. Если сработает, мне придется посыпать голову пеплом взять назад свои слова об отсутствии в DB-компонентах возможности подсчета на лету.
Ответить с цитированием
  #7  
Старый 27.09.2013, 15:40
Аватар для Uniq!
Uniq! Uniq! вне форума
Местный
 
Регистрация: 29.09.2010
Сообщения: 539
Версия Delphi: Delphi XE3
Репутация: 374
По умолчанию

У меня походу разбирательств с циклом всплыло такое решение:
Добавить 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  
Старый 27.09.2013, 16:36
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,015
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Я бы посоветовал бы не напрягаться.
1. Для подсчета произведения можно спокойно использовать вычисляемое поле (calcField), т.к. это значение ВСЕГДА можно вычислить, если оно понадобится (вспоминаем принципы проектирования БД - не надо хранить в базе то, что всегда можно вычислить).
2. Для подсчета суммы "на лету" можно либо воспользоваться готовым гридом, который это умеет (например, от DevExpress, вроде EhLib'овсеий тоже умеет), либо написать свой код (тут фокус в том, что надо запомнить текущую позицию курсора, отключить визуальную часть компонентов /там метод спец. есть/, пробежаться по датасету вычисляя сумму, потом вернуться на запомненную строчку и обратно подключить визуальную часть. Это будет работать быстро даже для большого кол-ва записей).
Ответить с цитированием
  #9  
Старый 27.09.2013, 16:37
Аватар для Mrak
Mrak Mrak вне форума
Местный
 
Регистрация: 26.01.2013
Адрес: МО
Сообщения: 438
Версия Delphi: XE2
Репутация: 17
По умолчанию

Цитата:
Сообщение от lmikle
... вроде EhLib'овсеий тоже умеет...
подтверждаю, умеет в Footer
__________________
Я за здоровый экстрим!
Спасибо за "спасибо")

Последний раз редактировалось Mrak, 27.09.2013 в 16:41.
Ответить с цитированием
Ответ


Delphi Sources

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 03:06.


 

Сайт

Форум

FAQ

RSS лента

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2023

ВКонтакте   Facebook   Twitter