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;