Sources
Delphi Russian Knowledge Base
DRKB - база знаний по Дельфи в рунете, составленная Виталием Невзоровым

5. Работа с таблицами в коде

01.01.2007
Vit

Пока мы рассмотрели самые простейшие и самые не эффективные операции над базами данных, которые нужны лишь в очень ограниченных случаях - их недостаток очевиден - операции роводятся только с одной записью и эти операции только визуальные. Чем это плохо? - это самый медленный способ работы с базами. Он годиться только для работы с данными в ручную, все остальные операции, которые не требуют визуализации не должны работать таким образом.

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

Сразу предупреждаю - КАТЕГОРИЧЕСКИ НЕ СЛЕДУЕТ ПЫТАТЬСЯ ИЗ КОДА МЕНЯТЬ ЗНАЧЕНИЯ В ВИЗУАЛЬНЫХ КОМПОНЕНТАХ, не следует пытаться менять или читать значения из DBGrid, DBEdit и т.д. Эти компоненты существуют только для работы оператора "вручную". Для доступа к данным из кода надо использовать только невизуальные компоненты типа TTable (в дальнейшем мы разберём и другие компоненты для работы с данными - но в любом случае это будут не визуальные компоненты).

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

1. Определить поле - задача очень простая.

Способов здесь 2:

Table1.FieldByName('Category')
Table1.Fields[1]

Оба выражения являются объектом наследованным от типа TField. Я не буду разбирать этот объект подробно, только приведу пример как можно пользоваться этим объектом для доступа к содержимому ячейки таблицы. Содержимое может быть разных типов, поэтому можно использовать следующие методы в зависимости от типа данных:

Table1.FieldByName('Category').AsString
Table1.FieldByName('Category').AsInteger
Table1.FieldByName('Category').AsBoolean
Table1.FieldByName('Category').AsDateTime
Table1.FieldByName('Category').AsFloat

Например, поставьте на форму кнопку, и на onClick напишите следующий код:

Showmessage(Table1.FieldByName('Category').AsString);

При нажатии на кнопку вы увидите содержимое столбца 'Category' для текущей записи. Аналогично для обращения по номеру:

Showmessage(Table1.Fields[1].AsString);

Обратите внимание, что на этапе компилляции компиллятор абсолютно не знает о реальном типе данных в поле таблицы. Это выяснится только при попытке выполнить строку. Что будет если типы не совпадают? Если тип можно конвертировать - то ничего страшного, например если у вас поле с целым числом 123, то обращение к полю через AsString выдаст результат - строку '123'. Но если типы не совместимы, то будет сгенерирована ошибка, например такая строка почти наверняка в нашем приложении приведёт к ошибке:

var i:integer;
...
i:=Table1.FieldByName('Category').AsInteger;
showmessage(inttostr(i));

Потому что реальные данные не могут быть приведены к целому типу.

Теперь давайте разбираться как нам добраться до нужной строки, другими словами, до нужной записи. Как я уже говорил мы можем работать только с одной "активной" записью, поэтому задача сводится к установке нужной записи "активной" (К знатокам баз данных - я упорно и намеренно обхожу стороной понятие "курсор" и попытаюсь провести повествование без его упоминания, с целью упрощения понимания материала, и не хочу углублятся в материал, без которого можно на первых порах обойтись). Итак, прежде всего Table компонент имеет 4 метода которые помогут нам пройти через все строки таблицы:

А также 2 полезных свойства:

Давайте на нашу форму положим компонент Memo (на сей раз обычное, а не dbMemo).

Вот этот простейший код позволит пройти таблицу от начала до конца и считать значения одного поля для всех записей в Memo:

Table1.First;//переход на первую запись
While not Table1.eof do //делать цикл пока таблица не закончится
begin
  Memo1.lines.add(Table1.fieldbyname('Category').AsString); //заносим в Мемо значение поля для текущей записи
  Table1.Next;//переходим на следующую запись
end;

Или это же самое можно сделать например так:

Table1.First;
For i=0 to Table1.recordcount-1 do
begin
  Memo1.lines.add(Table1.fieldbyname('Category').AsString); //заносим в Мемо значение поля для текущей записи
  Table1.Next;//переходим на следующую запись
end;

Второй способ гораздо хуже. Он имеет следующие недостатки:

    Table1.Last;
    Table1.First;
    For i=0 to Table1.recordcount-1 do
    begin
      Memo1.lines.add(Table1.fieldbyname('Category').AsString); //заносим в Мемо значение поля для текущей записи
      Table1.Next;//переходим на следующую запись
    end;

Несмотря на кажущуюся бессмысленность это работает.

Previous page:
4. Визуальные компоненты для DB
Top:
DRKB
Next page:
6. Поиск нужных данных