Форма для работы с тарифами и билетами - динамическое формирование SQL запроса

На этой форме (FormTicket) покажем три списка (рис. 24). Первый предназначен для отображения всех имеющихся тарифов. Второй показывает даты вылета и суммарное количество билетов по выбранному тарифу на указанную дату. Третий список выводит данные по всем билетам за указанное число по выбранному тарифу.

Форма для работы с тарифами и билетами - динамическое формирование SQL запроса - student2.ru

Рисунок 24 Форма для работы с тарифами и билетами

На этой же форме расположим кнопку, при помощи которой будет продаваться новый билет.

На форме размещаются следующие компоненты для работы с данными

Назначение запроса Компонент доступа к данным (IBQuery) Компонент модификации данных (IBUpdateSQL) Компонент источник данных DataSource
Выводит данные по всем тарифам (номер авиалиний, название аэропортов откуда и куда, тип салона, цена билета) IBQueryTarif DataSourceTarif IBUpdateSQLTarif
Даты вылета и количество проданных билетов по указанному тарифу IBQueryCntTick DataSourceCntTick DataSourceCntTick
Извлекает данные по билетам (ФИО пассажира, номер билета и место) IBQueryPass DataSourcePass DataSourcePass
Для динамического создания запросов IBQueryAsc    

Первый список (тарифы – IBQueryTarif) выводится при помощи запроса

select TR_AL_NUM, TR_AP_FROM, TR_AP_TO, TR_CODE, TR_COST, TR_SL_TYPE from TARIFF

Второй список (даты вылета – IBQueryCntTick) использует левое объединение, так как возможно, что по этому тарифу за это число не было продано ни одного билета.

SELECT count (TC.TC_NUM), f.fl_date FROM TARIFF TR

INNER JOIN flight f on f.fl_num = TR.tr_al_num

LEFT JOIN TICKET TC ON (TC.TC_TR_CODE = TR.tr_code AND TC.tc_fl_date = f.fl_date)

WHERE TR.TR_CODE = :tr

В качестве параметра запроса подставляется код тарифа при помощи события

procedure TFormTicket.DataSourceTarifDataChange(Sender: TObject;

Field: TField);

Begin

IBQueryCntTick.Close;

IBQueryCntTick.ParamByName('tr').AsInteger := IBQueryTarifTR_CODE.Value;

IBQueryCntTick.Open;

end;

Данные по проданным билетам получаем при помощи следующего запроса:

select P.pr_name, P.pr_name2, P.pr_name3, T.tc_fl_num, Cast(T.tc_row as char(2))||tc_lit from person P

inner join ticket T on T.tc_pr_code = P.pr_code

where T.tc_tr_code = :TR and T.tc_fl_date = :dt

В этот запрос нужно подставить два параметра – код тарифа и дату вылета. Эта подстановка производиться событием onDataChange для компонента DataSourceCntTick

procedure TFormTicket.DataSourceCntTickDataChange(Sender: TObject;

Field: TField);

Begin

IBQueryPass.Close;

//билеты по тарифу на день вылета

IBQueryPass.ParamByName('TR').AsInteger := IBQueryTarifTR_CODE.Value;

IBQueryPass.ParamByName('DT').AsDate := IBQueryCntTickFL_DATE.Value;

IBQueryPass.Open;

end;

Покупка нового билета

Рассмотрим, как наше приложение позволяет осуществлять покупку нового билета.

Прежде всего, нам нужно будет создать вспомогательную форму (FormNewTicket), при помощи которой мы сможем задать все атрибуты для нового билета (рис. 25). На форме будут располагаться компоненты TDBEdit отображающие сведенья о приобретаемом билете, полученные из запроса тарифы – IBQueryTarif. Отображаются следующие поля: номер авиалиний, название аэропортов откуда и куда, тип салона, цена билета. Редактор дат (DateTimePickerTicket) предназначен для задания даты вылета в билете. Три однострочных редактора (EditName, EditName2, EditName3) предназначены для задания фамилии, имени, отчества пассажира. Эти поля используются для поиска личности при помощи запроса с параметрами.

Решетка (DBGridPRS) предназначена для вывода списка личностей, из которых можно выбрать покупателя билета.

Под решеткой располагаются два обычных однострочных редактора, в которые выводятся номер билета и номер места.

Кроме визуальных компонент на форме размещаются компоненты для работы с данными

Назначение запроса Компонент доступа к данным (IBQuery) Компонент источник данных DataSource
Извлекает данные личности (код и ФИО) для продажи билета IBQueryPRS DataSourcePRS
Для подстановки динамически сгенерированного SQL запроса IBQueryAny  
Находит номер для вновь продаваемого билета IBQueryNewNum  

В нижней части формы располагаются две кнопки (TBitBtn). У одной из них свойство Kind равно bkOK – при нажатии на эту кнопку форма закроется (свойство ModalResult для формы будет присвоено mrOk) и будет создан новый билет. Эта кнопка имеет надпись «ОК». У второй кнопки свойство Kind установлено bkCancel – эта кнопка просто закрывает форму (свойство ModalResult для формы будет присвоено mrCancel).

Форма для работы с тарифами и билетами - динамическое формирование SQL запроса - student2.ru

Рисунок 25 Форма для покупки нового билета

Обсудим использование компонент для работы с данными детально.

Компонент IBQueryPRS выводит список личностей в зависимости от условия отбора, которые задаются при помощи параметров. Сам SQL запрос имеет вид:

SELECT PR_NAME, PR_NAME2, PR_NAME3, PR_CODE FROM PERSON

WHERE PR_NAME LIKE :NAME AND PR_NAME2 LIKE :NAME2 AND PR_NAME3 LIKE :NAME3

ORDER BY PR_NAME, PR_NAME2, PR_NAME3

Параметры запроса подставляются при любом изменении в заданной фамилии, имени или отчестве, т.е. в компоненте EditName, EditName2 или EditName3. Соответствующее событие имеет вид

procedure TFormNewTicket.EditNameChange(Sender: TObject);

Begin

IBQueryPRS.Close;

IBQueryPRS.ParamByName('NAME').AsString := EditName.Text + '%';

IBQueryPRS.ParamByName('NAME2').AsString := EditName2.Text + '%';

IBQueryPRS.ParamByName('NAME3').AsString := EditName3.Text + '%';

IBQueryPRS.Open;

end;

После отработки этого события в решетке DBGridPRS будет отображен список личностей, соответствующий введенным ограничениям. Чтобы выбрать одного человека, которому будет продан билет нужно щелкнуть по выбранной строке в решетке, при этом его фамилия, имя, отчество будут скопированы в EditName, EditName2, EditName3.

procedure TFormNewTicket.DBGridPRSDblClick(Sender: TObject);

Begin

EditName.Text := IBQueryPRSPR_NAME.Value;

EditName2.Text := IBQueryPRSPR_NAME2.Value;

EditName3.Text := IBQueryPRSPR_NAME3.Value;

end;

Компоненты IBQueryAny, IBQueryNewNum задействованы при первичном заполнении полей для нового билета.

Будем считать, что нумерация билетов на каждую авиалинию идет строго по нарастающей. Тогда IBQueryNewNum будет находить номер для вновь продаваемого билета при помощи SQL запроса

select Max(TC_NUM) + 1 from TICKET

WHERE TC_FL_NUM = :fl

Номер места в новом билете тоже будем проставлять автоматически. Если место последнего проданного билета на данный рейс и в данном салоне не последнее в ряду, то следующее место будет отмечаться следующей литерой, иначе следующее место будет в следующем ряду и обозначаться литерой 'А'. Выполняем этот алгоритм при помощи компонента IBQueryAny путем динамического создания текста запроса в зависимости от заданных параметров. Найденные номер ряда и литера места для нового билета будут помещены в публичные члены класса TFormNewTicket.

Public

sLit :String;

sNum :Integer;

Все требуемые поля задаются после нажатия на кнопку «Купить билет» при показе формы FormNewTicket. Вот событие OnShow для этой формы

procedure TFormNewTicket.FormShow(Sender: TObject);

Var

inRow : Integer;

Begin

with FormTicket do begin //данные передаются из формы FormTicket

//подсчитаем новый номер билета

IBQueryNewNum.Close;

IBQueryNewNum.ParamByName('fl').AsInteger :=

IBQueryTarifTR_AL_NUM.AsInteger;

IBQueryNewNum.Open;

EditNum.Text := IBQueryNewNum.Fields[0].AsString;

//подсчитаем новое место

//Ряд

IBQueryAny.SQL.Text := 'SELECT MAX(ticket.tc_row) FROM tariff '

+'INNER JOIN ticket ON (tariff.tr_code = ticket.tc_tr_code) '

+'WHERE tariff.tr_al_num = ' + IBQueryTarifTR_AL_NUM.AsString

+'AND tariff.tr_sl_type = ' + IBQueryTarifTR_SL_TYPE.AsString

+'AND ticket.tc_fl_date = ''' + DateToStr(DateTimePickerTicket.Date)

+'''';

IBQueryAny.Open;

sNum := IBQueryAny.Fields[0].AsInteger;

//Литера

IBQueryAny.SQL.Text := 'SELECT MAX(ticket.tc_lit)FROM tariff '

+'INNER JOIN ticket ON (tariff.tr_code = ticket.tc_tr_code) '

+'WHERE tariff.tr_al_num = ' + IBQueryTarifTR_AL_NUM.AsString

+'AND tariff.tr_sl_type = ' + IBQueryTarifTR_SL_TYPE.AsString

+'AND ticket.tc_fl_date = ''' + DateToStr(DateTimePickerTicket.Date)

+ '''' + ' AND ticket.tc_row = ' + IntToStr(sNum);

IBQueryAny.Open;

sLit := IBQueryAny.Fields[0].AsString;

//мест в ряду

IBQueryAny.SQL.Text := 'SELECT SP.SP_INROW FROM SALON_IN_PLANE SP '

+'INNER JOIN TARIFF T '

+'ON T.TR_SL_TYPE = SP.SP_SL_TYPE INNER JOIN AIRLINE AL '

+'ON AL.AL_NUM = T.TR_AL_NUM AND SP.SP_PL_CODE = AL.AL_PL_CODE '

+'WHERE T.TR_CODE = ' + IBQueryTarifTR_CODE.AsString;

IBQueryAny.Open;

inRow := IBQueryAny.Fields[0].AsInteger;

if sNum = 0 then begin

sNum := 1; //Первый билет

sLit := 'А';

Наши рекомендации