Interface

Begin

Begin

Begin

// Перевод таблицы в режим монопольного доступа

Tablel.Close;

Tablel.Exclusive:=true;

Tablel.Open;

// Добавление индекса

Tablel.Addlndex('indPosition', 'Position', [ixDescending, ixCaselnsensitive]);

// Закрытие режима монопольного доступа к таблице

Tablel.Close;

Tablel.Exclusive:=false;

Tablel.Open;

end;

 

Здесь к таблице, с которой связан набор данных Tablel, добавляется индекс indPosition, построенный по полю Position. Для нового индекса определяется порядок сортировки по убыванию значений и независимо от регистра букв.

Процедура DeleteIndex (const Name: String) удаляет из таблицы индекс, имя которого задано параметром Name. При попытке удаления несуществующего ин­декса генерируется исключитель-ная ситуация.

В программе удаление индекса из таблицы может быть реализовано так:

Tablel.Deletelndex('indPosition') ;

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

Для доступа к информации обо всех индексах, определенных для таблицы и, соответст-венно, для связанного с ней набора данных, можно использовать свой­ство indexDefs типа TindexDefs. Это свойство доступно как на этапе разработки, так и на этапе выполнения приложения. Класс TindexDefs в свою очередь также имеет полезные свойства и методы, которые мы сейчас и рассмотрим.

Перед работой с индексами всегда рекомендуется вызывать метод UpDate, кото­рый производит обновление информации об индексах так, чтобы значение свойства IndexDefs отражало реальное состояние с учетом сделанных изме­нений.

 
 

Свойство Count типа Integer содержит количество индексов и доступно для чте­ния. Управление количеством индексов осуществляется косвенно, т. е. через другие свойства и методы.

Свойство Items [Index: Integer] типа TindexDef представляет собой список, содержащий информацию обо всех индексах таблицы. Переменная Index указы­вает номер индекса в списке, отсчет начинается с нуля. Тип TindexDef (не пу­тать с классом TindexDefs) является классом и, в свою очередь, также имеет свойства, основными из которых являются Name, Fields и Options.

Замечание

При доступе к информации об индексах можно опускать название свойства items. Например, для чтения в редактор Editl списка полей, составляющих второй индекс, можно использовать следующие эквивалентные по действию операторы:

Editl.Text:=Tablel.IndexDefs[1].Fields;

или

Edit1.Text:=Tablel.IndexDefs.Items[1].Fields;

 

Свойство Name типа String содержит имя индекса. Для индексов, построенных на основе выражений (таблицы dBase), и для главного индекса таблиц Paradox вместо названия возвращается пустая строка.

Свойство Fields типа String содержит названия полей, по которым построен индекс. Если в индексе используется несколько полей, то их названия разделя­ются точкой с запятой.

Свойство Options типа TIndexOption содержит параметры индекса, заданные при его создании.

Рассмотрим работу со списком индексов и индексных полей на конкретном примере.

На форме расположены следующие компоненты: сетка DBGrid, в которой ото­бражаются записи таблицы БД, два списка ListBox с соответствующими надпи­сями, а также две кнопки Button. При нажатии кнопки Button1 с названием Ин­дексы в список ListBoxl загружается список индексов, определенных для набо­ра данных Table1, а в список ListBox2 — список полей, образующих эти индексы (рис. 7.2). Так как компонент Tablel связан с таблицей Paradox, то название главного индекса, построенного по полю pcode, содержит пустую строку.

Обработчик события нажатия кнопки Button1 выглядит так:

procedure TForml.ButtonlClick(Sender: TObject);

var n: integer;

for n:=0 to Tablel.IndexDefs.Count-1 do begin

ListBoxl.Items.Add(Tablel.IndexDefs[n].Name);

ListBox2.Items.Add(Tablel.IndexDefs[n].Fields);

end;

end;

 

Рис. 7.2. Получение списка индексов и полей

 

Для получения списка имен индексов можно использовать метод GetItemNames(List: TStrings). Он возвращает список имен индексов через па­раметр List, в качестве которого можно использовать любой объект типа TStrings, например, ListBoxItems.

 

Получение списка имен индексов в программе может выглядеть так:

ListBoxl.Items.Clear;

Tablel.GetItemNames(ListBoxl.Items);

 

Для добавления и удаления индексов используются методы Add и Clear. Про­цедура Add (const Name, Fields: String; Options: TIndexOptions) добавляет новый индекс. Параметры этой процедуры не отличаются от параметров метода Addindex набора данных Table, однако для метода Add не требуется перевод таблицы в режим монопольного доступа, что делает его использование более удобным.

Замечание

Для таблиц Paradox при определении ключа (главного индекса) название ин­декса не задается, т. к. этот индекс не именуется.

 

Процедура Clear удаляет все индексы, содержащиеся в списке индексов. Вот как удаление и добавление индексов к таблице реализуется в программе:

Tablel.IndexDefs.Clear;

Tablel.IndexDefs.Add('' , 'Number', [ixPrimary, ixUnique]);

Tablel.IndexDefs.Add('indMain', 'Code;Position',

[ixDescending, ixCaseInsensitive]);

 

В этом примере из набора данных Tablel, связанного с таблицей Paradox, уда­ляются все индексы и создаются два новых индекса: первичный индекс, постро­енный по полю Number, и вторичный индекс indMain, построенный по полям Code и Position.

Ряд методов предназначен для поиска индексов в списке, например, IndexOf, Find и FindIndexForFields. Их удобно использовать в случае, когда индексы или их поля вводятся пользователем на этапе выполнения приложения. Перед ис­пользованием таких индексов целесообразно проверять, существуют ли они в списке индексов, т. к. в противном случае мы рискуем получить исключи­тельную ситуацию.

Функция IndexOf (const AName: String): Integer осуществляет поиск индекса по имени, заданному параметром AName. В качестве результата возвращается но­мер индекса в свойстве items. В случае неудачного поиска возвращается значе­ние -1.

Рассмотрим следующий пример на поиск индекса:

procedure TForml.Button2Click(Sender: TObject);

if Tablel.IndexDefs.IndexOf(Editl.Text) = -1 then begin

MessageDlg('Индекс отсутствует!', mtError, [mbOK], 0);

if Editl.CanFocus then Editl.SetFocus;

end;

end;

 

Здесь при нажатии кнопки Button2 выполняется проверка существования ин­декса, имя которого введено в поле редактирования Editl. При отсутствии в наборе данных Tablel указанного индекса выдается сообщение об ошибке, и фокус ввода устанавливается на Editl.

Функция FindIndexForFields (const Fields: String): TIndexDef осуществляет поиск индекса по списку полей, заданному параметром Fields. В случае успеш­ного поиска функция возвращает информацию об индексе, если же индекс от­сутствует, то генерируется исключительная ситуа-ция.

Замечание

Если не найден индекс, поля которого полностью совпадают с заданными, но есть индексы, которые включают в себя все заданные поля, то в качестве ре­зультата возвращается первый такой индекс.

 

При запуске приложения информация об индексах таблицы считывается с дис­ка из соответствующих индексных файлов. При динамическом, т. е. в процессе выполнения приложения, изменении индексов содержимое индексных файлов остается прежним. При необходимости программист должен предусмотреть со­хранение новой информации на диске для ее последующего применения. Для этого можно использовать свойство StoreDefs типа Boolean, которое указывает, нужно ли сохранять информацию об индексах на диске. При любых изменениях в индексах этому свойству нужно установить значение True, и тогда информа-ция об индексах будет автоматически сохранена на диске. Если изменения в индексах сохранять не нужно, то достаточно установить свойству StoreDefs значение False, и изменения в индексах будут действовать только при выполне­нии приложения.

 

1.5. Особенности набора данных Query

Компонент Query представляет собой набор данных, записи которого формиру­ются в результате выполнения SQL-запроса и основаны на реляционном спосо­бе доступа к данным. При работе с удаленными БД рекомендуется использовать именно набор данных Query.


Замечание

При работе с удаленными БД следует обращаться к средствам языка SQL. Это относится и к таким операциям, как перемещение по набору данных или встав­ка в него записей. Если же для компонента Query используются методы типа Next или insert, то вместо реляционного способа доступа к удаленным дан­ным будет применен навигационный. В результате набор данных Query будет мало чем отличаться от набора данных Table.

 

В отличие от компонента Table, набор данных Query может включать в себя записи более чем одной таблицы БД.

Текст запроса, на основании которого в набор данных отбираются записи, со­держится в свойстве sql типа TStrings. Запрос включает в себя команды на языке SQL и выполняется при открытии набора данных. Запрос SQL иногда называют SQL-программой.

При формировании запроса на этапе разработки приложения можно использо­вать текстовый редактор (рис. 7.3), вызываемый через Инспектор объектов двойным щелчком в области значения свойства SQL.


Рис. 7.3.Редактирова­ние запроса SQL


SQL-запрос также можно формировать и изменять динамически, внося измене­ния в его текст (значение свойства sql компонента Query) непосредственно при выполнении приложения.

Замечание

В процессе формирования SQL-запроса проверка его правильности не произ­водится, и если в запросе имеются ошибки, то они выявляются только при от­крытии набора данных. Одним из вариантов предотвращения ошибок в SQL-запросе является его предварительная отладка, например, с помощью про­граммы Database Desktop.

Рассмотрим пример приложения — простейшего редактора, позволяющего подготавливать и выполнять SQL-запросы. На рис. 7.4 показана форма прило­жения при его выполнении. Кроме визуальных компонентов, форма содержит два компонента доступа к данным Queryl и DataSourcel, которые при выполне­нии приложения не видны.

Рис. 7.4.Приложение-редактор SQL-запросов

 

Редактирование SQL-запроса осуществляется с помощью компонента Memoi. На­бранный запрос выполняется при нажатии кнопки Buttonl с заголовком Вы­полнить,а результат выполнения отображается в компоненте DBGrid1.

При наличии в тексте SQL-запроса ошибки генерируется исключительная си­туация и выдается сообщение об ошибке (рис. 7.5), а результат запроса оказы­вается не определен. При этом набор данных Queryl автоматически закрывается.

Значения свойств DataSet источников данных DataSourcel И DataSource компо­нента DBGridi, с помощью которых организуется взаимодействие компонентов Queryl, DataSourcel и DBGridi, устанавливаются при создании формы. В после­дующих примерах приложений значения этих свойств задаются через Инспек­тор объектов, поэтому операторы, присваивающие свойствам необходимые зна­чения, в модуле формы отсутствуют.


 

Рис. 7.5. Сообщение об ошибке в тексте SQL-запроса

 


Приведем код модуля uSQLEdit формы Forml приложения:

 

unit uSQLEdit;