Смекни!
smekni.com

Особенности проектирования баз данных (стр. 3 из 3)

На форме отображения и редактирования данных из таблицы BOOKS для поиска разместим следующие компоненты:

· Edit1 – для ввода пользователем значений KeyValues.

· Button1 – для активации поиска.

· Несколько компонентов CheckBox для указания списка полей для поиска, т. е. значения KeyFields.

В процедуре – обработчике события нажатия на кнопку Button1 сначала производится сбор строки списка полей KeyFields в соответствии с указаниями флажков CheckBox. Затем это значение вместе со значением поля Edit1 отправляется в функцию LocateNext через пользовательскую функцию loc(Fields,Values), описанную в модуле Unit2 (в модуле Unit2 описан класс TDataModule2 (форма модуля данных) в котором определён и компонент «BOOKS_DataSet: TIBDataSet;»).

Аналогично в программе организован поиск в таблицах PUBLISHERS и READERS.

Фильтрация данных

Зададим фильтрацию значений в таблице BOOKS.

На форме таблицы BOOKS поместим компоненты CheckBox для того, чтобы пользователь имел возможность включать и выключать фильтр по отдельным полям. Фильтр производится только по тем полям, для которых выбраны соответствующие им переключатели CheckBox, для этого в программе определены логические переменные (в модуле Unit2) для указания, следует ли фильтровать записи по введённому пользователем значению соответствующего поля. Для включения фильтра служит кнопка «Включить фильтр» где производится присвоение переменным (модуля Unit2) введённых значений указанных полей, после чего включается фильтр заданием свойству BOOKS_DataSet.Filtered значения True. После того, как свойству Filtered компонента TIBDataSet будет присвоено значение True то производится переоткрытие набора данных, но при этом выполняется метод OnFilterRecord этого компонента. Процедура – обработчик этого метода определена следующим образом:

procedureTDataModule2.BOOKS_DataSetFilterRecord(DataSet: TDataSet; varAccept: Boolean);

где DataSet соответствующий набор данных. Эта процедура выполняется для каждой записи и если возвращаемый этой процедурой параметр Accept равен True, то текущая запись отображается, в противном случае – нет. Пример фильтра:

if (DataSet['NAME'] <> Name_) thenAccept := False;

где NAME – название поля, Name_ – переменная, значение которой сравнивается со значением этого поля текущей записи.

В программе определён следующий фильтр:

procedure TDataModule2.BOOKS_DataSetFilterRecord(DataSet: TDataSet;

var Accept: Boolean);

begin

Accept := True;

if P1 then if (DataSet['NAME'] <> Name_) then Accept := False;

if P2 then if (DataSet['K_PAGES'] < K_Pages_1) then Accept := False;

if P3 then if (DataSet['K_PAGES'] > K_Pages_2) then Accept := False;

if P4 then if (DataSet['DATE_ISSUE'] < Date_1) then Accept := False;

if P5 then if (DataSet['DATE_ISSUE'] > Date_2) then Accept := False;

if P6 then if (DataSet['ID_PUBLISHERS'] <> Id_pub) then Accept := False;

if P7 then if (DataSet['COVER'] <> Cov) then Accept := False;

if P8 then if (DataSet['TIRAZ'] < Tiraz_1) then Accept := False;

if P9 then if (DataSet['TIRAZ'] > Tiraz_2) then Accept := False;

if 10 then if (DataSet['ID_ABONENT'] <> Id_ab) then Accept := False;

end;

Логические переменные P1 – P10 хранят значения, соответствующие выбранным флажкам CheckBox, и если флажок выбран, то соответствующая ему переменная будет равна True, а значит, будет производиться фильтр по значению этого поля. Изначально переменная Accept принимает значение True, т. е. считается, что строка проходит, если не будет показано невыполнение хотя бы одного условия фильтрации. Поэтому здесь проверяется невыполнение каждого из заданных условий (например вместо «DataSet['NAME'] = Name_» проверяется «DataSet['NAME'] <> Name_» и ставится не «Accept:= True» в случае выполнения этого условия, а «Accept := False»). Достаточно невыполнения одного условия, чтобы строка не прошла, т. е. переменная Accept принимает значение False.

Аналогично зададим фильтр и для других таблиц.

Вывод отчёта

Организуем вывод отчётов в программе. Для начала создадим запрос на выборку записей таблицы BOOKS, где вместо кодов издательства и читателя будет выводиться вся о них информация, полученная из таблиц PUBLISHERS и READERS. Для этого поместим компонент IBQuery, назовём его BOOKS_Query и в свойстве SQL запишем:

select all BOOKS.NAME, BOOKS.COVER, BOOKS.TIRAZ, BOOKS.K_PAGES, PUBLISHERS.NAME, PUBLISHERS.CITY, READERS.FIO, READERS.ADDRESS, READERS.TELEPHONE, BOOKS.DATE_ISSUE

from (BOOKS inner join PUBLISHERS on BOOKS.ID_PUBLISHERS= PUBLISHERS.ID_PUBLISHERS) left join READERS on BOOKS.ID_ABONENT= READERS.ID_ABONENT

order by BOOKS.NAME;

Запрос выводит поля из всех трёх таблиц. Таблицы BOOKS и PUBLISHERS связаны по равенству поля ID_PUBLISHERS, а полученная в результате такой связи выборка дополнительно связана с таблицей READERS по равенству поля ID_ABONENT. Здесь благодаря связи leftjoinв запрос выводятся записи, содержащие в поле BOOKS.ID_ABONENT значение NULL. Дополнительно к записям применяется сортировка по значению поля BOOKS.NAME.

Установим свойство Active компонента BOOKS_Query в True. Если при этом не появится сообщение об ошибке, то запрос SQL введён без ошибок.

Также поместим на модуль данных компонент DataSourse, назовём его BOOKS_Query_Source и в свойстве DataSet укажем BOOKS_Query.

Создадим новую форму и поместим на неё компонент DBGrid1 в свойстве DataSourse которого укажем DataModule2.BOOKS_Query_Source. На форме расположим кнопку «Вывести отчёт», по нажатию на которую будет выводиться отчёт запроса BOOKS_Query.

Для создания непосредственно отчёта создадим для него новую форму и поместим на неё компонент QuickRep. И укажем в свойстве DataSetDataModule2.BOOKS_Query. Укажем в свойстве Page.Orientation = poLandscape (Пейзажная ориентация страницы). У свойства Bands установим в True следующие подсвойства: HasDetail, hasTitle, PageHander. Поместим на компонент QuickRep в область Detail компоненты QRDBTextдля каждого поля, в свойстве DataSet которых укажем DataModule2.BOOKS_Query, а в свойстве DataField соответствующее поле. В область Title поместим такое же количество компонентов QRLabel для названий атрибутов, и укажем эти названия в свойстве Caption этих компонентов. Расположим на форме компоненты QRTextFilter, QRHTMLFilter для сохранения отчетов в форматах HTML, TXT. В области отчёта PageHander поместим компонент QRSysData для вывода текущей даты, для чего в свойстве Data установим значение qrsDate. Те же компоненты используем и для вывода текущего времени и текущего номера страницы.

Ввод SQL запросов и вывод хранимых процедур

Работая с приложением баз данных, пользователь должен иметь возможность задавать SQL запросы, некоторые из которых сохранены на сервере в виде хранимых процедур. Для обеспечения такой возможности следует на главную форму поместить компонент для ввода текста Memo, в который пользователь и будет вводить текст запроса. Затем на модуль данных поместим компонент IBQuery1: TIBQuery1 (соответственно и DataSource1: TDataSource1), создадим форму для вывода результата и поместим на неё компонент DBGrid1: TDBGrid1. Затем на главную форму поместим кнопку и в обработчике её нажатия зададим перезапись введённого запроса из текстового поля в свойство SQL компонента IBQuery1 после чего сделаем компонент IBQuery1 активным и отобразим форму вывода результата.

Если в запросе указать вывод хранимой процедуры, просто указав

select * from KOL_BOOKS_TIRAZ;

или

select * from BOOKS_LIBRARY;

то выполнится запрос, определённый в этой процедуре.

Листинг процедуры – обработчика события нажатие на кнопку «Вывести результат запроса»:

procedure TForm1.Button10Click(Sender: TObject);

var i:integer;

begin

DataModule2.IBQuery1.Active:=False;

DataModule2.IBQuery1.SQL.Clear;

for i:=0 to Memo1.Lines.Count do

begin

DataModule2.IBQuery1.SQL.Append(Memo1.Lines[i]);

end;

DataModule2.IBQuery1.Active:=True;

Form10.Show;

end;

Для хранимой процедуры с входными параметрами предварительно нужно указать значения этих параметров, поэтому вызов хранимой процедуры BOOKS_LIST_PERIOD организован отдельно. Листинг процедуры, выполняющей вызов этой процедуры в программе:

procedure TForm1.Button9Click(Sender: TObject);

begin

DataModule2.IBQuery1.SQL.Clear;

DataModule2.IBQuery1.SQL.Add('select * from BOOKS_LIST_PERIOD(' +#39+MaskEdit1.Text+#39+','+#39+MaskEdit2.Text+#39+');');

DataModule2.IBQuery1.Active:=true;

Form9.Show;

end;

Здесь при помощи процедуры Add добавляется запись к свойству SQL компонента IBQuery1 (предварительно оно очищается при помощи процедуры Clear). MaskEdit1.Text и MaskEdit2.Text – значения полей ввода значений входных параметров, #39 – ASCII код одинарной кавычки, кавычки нужны для заключения в них значений входных параметров хранимой процедуры в SQL запросе. Затем активируется компонент IBQuery1 и отображается форма вывода результата хранимой процедуры.

Список литературы

1. Ковязин С., Востриков С. Мир InterBase. Архитектура, администрирование и разработка приложений баз данных в InterBase/ Firebird/ Yaffil. – М.: КУДИЦ – ОБРАЗ, 2005. – 496 с.

2. Хомоненко А.Д., Гофман В.Э. Работа с базами данных в Delphi. – СПб.: БХВ – Петербург, 2005. – 640с.

3. Кондзюба С.П., Громов В.Н. Delphi 6. Базы данных и приложения: Лекции и упражнения. – Киев: ДиаСофт, 2001. – 576 с.

4. http://www.ibase.ru/devinfo/ibfaq.htm

5. http://www.piter.com/lib/978527200003/sql7.phtml?fil=Ch12

6. http://www.codenet.ru/progr/delphi/stat/SQL-Delphi.php