Всем привет, опять же, пишу статью про ADO, а также по просьбе читателя моего блога, который попросил рассказать, как в БД можно работать с вычисляемыми полями (чтобы значение вычисляемого поля сразу менялось, при вводе нового значения), на примере БД — MS Access. Я расскажу 2 способа работы с вычисляемые полями, а на примере покажу только один способ. Ну, первый способ состоит в том, что все поля, в том числе и вычисляемое, мы создаем сразу в БД - MS Access, причем тип данных, поля, в котором будет менять значение — указываем Вычисляемое поле.

Что касается второго способа, то вычисляемое поле, мы создадим в нашем проекте, через компоненты TAdoQuery или TAdoTable.

Ну и сразу скажу, что есть, не очень правильный 3 метод, при котором можно использовать TTimer.

Давайте начнем с нашей БД.

У меня в БД имеет следующую структуру:

Итак, БД в MS Access у нас создана, теперь переходим к самому проекту  в Delphi, на форме у меня следующие компоненты:

  • TDataSource
  • TDBGrid
  • TADOConnection
  • TADOQuery
  • TButton

Теперь, делаем подключение к нашей БД, как это делать, мы рассматривали в статье, так что заострять внимание на этом, я не буду. Далее, нам необходимо все наши компоненты связать между собой, ну вот и приступим. Выделяем компонент TADOQuery и в свойстве Connection указываем — TADOConenction. Далее, выделяем компонент TDataSource и в свойстве DataSet указываем TADOQuery. Затем, выделяем компонент TDBGrid и в свойстве DataSource указываем TDataSource.

Все, теперь добавим все наши поля. Для этого, нам необходимо активировать наш запрос и подключение. В свойстве компонента TADOConenctionConnected устанавливаем True, а в свойстве компонента TADOQuery - SQL, напишем следующий запрос

SELECT * FROM Test

Имя, нашей таблицы — Test. Ну и далее, активируем наш запрос, в свойстве Active, компонента TADOQuery устанавливаем в True.

Далее нажимаем, двойным щелчком мыши по компоненту TADOQuery и появляется окно:

В данном окне, нажимаем правой кнопкой мыши, и из контекстного меню, выбираем пункт Add all fields. В список добавиться все наши поля таблицы.

Ну, а теперь создадим наше Вычисляемое поле. Для этого, в данном окне, нажимаем правой кнопкой мыши и из контекстного меню выбираем пункт New Field, после чего появиться окно, где необходимо заполнить поля, как показано на рисунке:

Указываем имя нашего вычисляемого поля, устанавливаем указатель на Calculated и указываем тип данных — Integer, можно и с плавающей точкой, какой Вам удобно.

Ну, а дальше, выделяем компонент TADOQuery и на событие OnCalcFields напишем следующий код:

procedure TForm1.ADOQuery1CalcFields(DataSet: TDataSet);
begin
   ADOQuery1Sum.AsInteger:=ADOQuery1Values.AsInteger*ADOQuery1Count.AsInteger;
end;

Не забываем, что свойство AutoCalcFields, компонента TADOQuery должно быть установлено в True

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

Исходник можно скачать тут


Мне повезло что я нашёл сервис, который успешно создает недорогие сайты и радует своей стабильностью.


Метки: , , , , , , ,




К записи “Работа с ADO в Delphi. Часть 6. Вычисляемые поля” оставлено комментариев: 24.

  1. zerdalert:

    Спасибо Андрей53!!! Классный пример. А я как только не пробовал, не получалось. Оказывается просто как и все гениальное. У тебя на сайте информации по базам данных, хватит на добротный учебник. И я думаю, если бы удалось издать, он бы пользовался популярностью, по крайней мере среди начинающих (как минимум). Спасибо что помогаешь разбираться и не оставляешь вопросы без внимания.
    :)

  2. zerdalert:

    Пробовал повторить
    procedure TForm1.ADOQuery1CalcFields(DataSet: TDataSet);
    begin
    ADOQuery1Sum.AsInteger:=
    ADOQuery1Values.AsInteger*ADOQuery1Count.AsInteger;
    end;
    вылетали ошибки, хотя в исходнике все также прописано и работает.
    Попробовал прописать столбцы через fields
    begin
    AdoQuery1.Fields.FieldByName(‘Ост’).asInteger:=
    AdoQuery1.Fields.FieldByName(‘Приход’).asInteger-AdoQuery1.Fields.FieldByName(‘Расход’).asInteger;
    end;
    Заработало.
    Может он именно на русские названия ругался,
    или то что вместо обычного Grida я использую DBGridEh?
    :)

    • Andrey53:

      Нет, то что вместо стандартного грида используешь DBGRidEh не в этом проблема, а ошибка хоть какая вылетала?

  3. zerdalert:

    Вот
    [error] unit1.pas(36)Illegal character in input file ‘О'($CE)
    [error] unit1.pas(36)Illegal character in input file ‘П'($CF)
    [error] unit1.pas(36)Illegal character in input file ‘Р'($DO)

    ‘О’- я так понял, первая буква слова Остаток, а ‘П’и’Р’ по ходу Приход и Расход.

  4. zerdalert:

    Ну да. Через Fields и все получилось :)

  5. zerdalert:

    Сегодня решил по экспериментировать. Добавил к примеру кнопку, на событии онклик прописал ADOQuery1.Insert; Но при нажатии, строка почему то не добавляется.
    Еще иногда выскакивает ошибка, ADOQuery1:DataSet not in edit or insert mode

  6. zerdalert:

    Не, у себя…
    Может разница в версиях Delphi? Я Delphi7 осваиваю.

  7. zerdalert:

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

  8. zerdalert:

    Все нашел блин, — причина как обычно моя невнимательность…

    • Andrey53:

      внимательней будь, просто так без кода и без проетка тяжелова-то найти обшибку, ты выкладывай код чуть что

  9. ДИЛЯ:

    что написать на кнопку найти, у меня выводить ошибку, помогите!!!

    • Andrey53:

      какой код у Вас на кнопке найти, как поиск осуществляете? запросами, фильтрацией? функцией?

  10. FeDosz:

    Большое спасибо за статью! Единственное, не получается привязать вычисление двух полей DBGrid к кнопке. Т.е. по нажатию баттона, два поля с числовыми значениями складываются, а результат должен отображаться в третьей колонке. Не могли бы вы подсказать, как реализовать эту функцию?

  11. FeDosz:

    Делаю по такому же принципу, как описано для события OnCalcFields, но не получается, выдается ошибка. Если меняешь значения для одного из полей и рассчитываешь, то работает, для всей таблицы со значениями не работает. В чем может быть проблема?

  12. Skarabey:

    Здравствуйте большое спасибо за статью.
    Помогите пожалуйста я еще плохо разбираюсь с базами данных и не могу понять куда сохраняется сумма складываемая из двух полей?
    В базе Access поле которое создали через Delphi 7 нету соответственно и значений тоже нету. Открываю прогу значения есть.
    Можно ли сделать чтобы в Access записывались вычисляемые значения ?

  13. Studentka:

    Здраствуйте, помогите, пожалуйста,
    у меня база по учету выдачи книг читателям. Мне необходимо сделать, чтобы автоматически в DBGrid ложились данные (в DBGrid должно быть количество строк равное количеству дней в месяце,за который мы хотим получить отчет) в первый столбец должно ложится число читателей, пришедших за день в библиотеку, во-второй столбец, число школьников, в-третий, число студентов и т.д. и так 30 строк, если, например, за апрель месяц. Мне не понятно, как нужно указать день, за который нужно подсчитать(((

    • Andrey:

      Не совсем понял, но в Delphi можно определить количество дней в месяце, в зависимости от этого количества Вы сможете создать таблицу в БД с нужным количество строк!

  14. Александр:

    Еще один способ, при котором в DBGrid (DBGridEh) организовывается колонка, где отображается рассчитанное значение или, вообще, любая другая строка.
    В списке колонок DBGrid создается еще одна, которая не связывается ни с каким полем таблицы БД.
    В процедуре обработки события OnDrawColumnCell гриды происходит обработка данных, получение и вывод результата:
    procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
    DataCol: Integer; Column: TColumn; State: TGridDrawState);
    var
    D : string;
    R : TRect;
    begin
    if Column.Index = 6 then begin //индекс дополнительной колонки
    //операторы вычислений или любые другие
    R := Rect;
    InflateRect(R, 0, -2);
    DrawText(DBGrid1.Canvas.Handle, PChar(D), -1, R, DT_Center);
    end;
    end;

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

  15. Роман:

    А можно как-нибудь фильтровать по вычисляемому полю? Пробовал, не получилось!
    {
    int n;
    n=2500;
    ADOTable1->Filtered=false;
    ADOTable1->Filter= «(Отработано=’ «+IntToStr(n)+» ‘)»;
    ADOTable1->Filtered=true;
    DBChart1->RefreshData();}

    Поле «отработано» — вычисляемое!
    Заранее спасибо!

Оставить комментарий на Andrey53

Вы можете использовать следующие теги:

*