Программирование с C++ Builder



Выбор информации из базы данных



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

Большинство систем управления базами данных позволяют выполнять выборку нужной информации путем выполнения запросов. Пользователь формулирует запрос, указывая критерий, которому должна удовлетворять интересующая его информация, а система выводит записи, удовлетворяющие запросу.

Для выборки из базы данных записей, удовлетворяющих некоторому критерию, предназначен компонент Query (рис. 5.17).



Рис. 5.17. Компонент Query


Компонент Query, как и компонент Table, представляет собой записи базы данных, но в отличие от последнего он представляет не всю базу данных (все записи), а только ее часть — записи, удовлетворяющие критерию запроса.

В табл. 5.13 перечислены некоторые свойства компонента Query.

Таблица 5.13. Свойства компонента Query


Свойство

Определяет

Name

Имя компонента. Используется компонентом DataSource для связи результата выполнения запроса (набора записей) с компонентом, обеспечивающим просмотр записей, например DBGrid

SQL

Записанный на языке SQL запрос к базе данных (к таблице)

Active

При присвоении свойству значения true активизируется процесс выполнения запроса

RecordCount

Количество записей, удовлетворяющих критерию запроса


Для того чтобы во время разработки программы задать, какая информация должна быть выделена из базы данных, в свойство SQL надо записать запрос — команду на языке SQL (Structured Query Language, язык структурированных запросов).

В общем виде SQL-запрос на выборку данных из базы данных (таблицы) выглядит так:

SELECT СписокПолей
 FROM Таблица
 WHERE
(Критерий)
 ORDER BY СписокПолей

где:

  •  SELECT — команда "выбрать из таблицы записи и вывести содержимое полей, имена которых указаны в списке";
  •  FROM — параметр команды, который определяет имя таблицы, из которой нужно сделать выборку;
  •  WHERE — параметр, который задает критерий выбора. В простейшем случае критерий — это инструкция проверки содержимого поля;
  •  ORDER BY — параметр, который задает условие, в соответствии с которым будут упорядочены записи, удовлетворяющие критерию запроса.


Например, запрос

SELECT Date_F, Task_F 
FROM ':organizer:org.db' 
WHERE ( Date_F = '09.02.2003')
 ORDER BY Date_F

обеспечивает выборку записей из базы данных organizer (из таблицы org.db), у которых в поле Date_F находится текст 09.02.2003, т. е. формирует список мероприятий, назначенных на 9 февраля 2003 года.

Другой пример. Запрос

SELECT Date_F, Task_F
 FROM ':organizer:org.db1
WHERE
( Date_F >= '10.02.2003') AND ( Date_F <= 46.02.2003')
ORDER BY Date_F

формирует список дел, назначенных на неделю (с 10 по 16 февраля 2003 года).

Запрос может быть сформирован и записан в свойство SQL компонента Query во время разработки формы или во время работы программы.

Для записи запроса в свойство SQL во время разработки формы используется редактор списка строк (рис. 5.18), окно которого открывается в результате щелчка на кнопке с тремя точками в строке свойства SQL (в окне Object Inspector).



Рис. 5.18. Ввод SQL-запроса во время разработки формы приложения


Сформировать запрос во время работы программы можно при помощи метода Add, применив его к свойству SQL компонента Query.

Ниже приведен фрагмент кода, который формирует запрос (т. е. записывает текст запроса в свойство SQL компонента Query) на выбор информации из таблицы org базы данных organizer. Предполагается, что строковая переменная today (тип AnsiString) содержит дату в формате dd/mm/yyyy.

Form1->Query1->SQL->Add("SELECT Date_F, Task_F");
Form1->Query1->SQL->Add("FROM ':organizer:org.db'");
Form1->Query1->SQL->Add("WHERE (Date_F = '" + today + "')");
Form1->Query1->SQL->Add("ORDER BY Date_F");

Если запрос записан в свойство SQL компонента Query во время разработки формы приложения, то во время работы программы критерий запроса можно изменить простой заменой соответствующей строки текста запроса.

Например, для запроса:

SELECT Date_F, Task_F
FROM ':organ!zer:org.db'
 WHERE
( Date_F = '09.02.2003')
ORDER BY Date_F

инструкция замены критерия выглядит так:
Queryl->SQL->Strings[3] = "(Date_F = '" + tomorrow + "')";

Следует обратить внимание на то, что свойство SQL является структурой типа TStrings, в которой строки нумеруются с нуля.

Для того чтобы пользователь мог выбирать информацию из базы данных, в форму разрабатываемого приложения надо добавить кнопки Сегодня, Завтра, Эта неделя и Все (рис. 5.19). Назначение этих кнопок очевидно. Также в форму добавлены два компонента Label. Поле Label1 используется для отображения текущей даты. В поле Label2 отображается режим просмотра базы данных.



Рис. 5.19. Окончательный вид формы


Функции обработки события click на кнопках Сегодня, Завтра и Эта неделя приведены в листинге 5.1. Каждая из этих функций изменяет соответствующим образом сформированный во время разработки формы SQL-запрос. Для получения текущей даты функции обращаются к стандартной функции NOW, которая возвращает текущую дату и время. Преобразование даты в строку символов выполняет стандартная функция FormatDateTime.

Листинг 5.1. Обработка события Click на кнопках Сегодня, Завтра и Эта неделя

// Щелчок на кнопке Сегодня 
void __fastcall TForml::ButtonlClick(TObject *Sender) 
{ 
AnsiString today = FormatDateTime("dd/mm/yyyy",Now());
Forml->Label2->Caption = "Сегодня";
// изменить критерий запроса
Queryl->SQL->Strings[3] = "(Date_F = '" + today + "')";
// выполнить запрос Forml->Queryl->Open();
Forml->DataSourcel->DataSet = Forml->Queryl;
if ( ! Forml->Queryl->RecordCount)
{
ShowMessage("Ha сегодня никаких дел не запланировано!");
} }
// щелчок на кнопке Завтра
void __fastcall TForml::Button2Click(TObject *Sender)
{ <
AnsiString tomorrow = FormatDateTime("dd/mm/yyyy", Now() +1);
Forml->Label2->Caption = "Завтра";
// изменить критерий запроса
Queryl->SQL->Strings[3] = "(Date_F = '" + tomorrow + "')";
// выполнить запрос Forml->Queryl->Open();
Forml->DataSourcel->DataSet = Forml->Queryl;
if ( ! Forml->Queryl->RecordCount)
{
ShowMessage("На завтра никаких дел не запланировано!");
} }
// щелчок на кнопке Эта неделя
void __fastcall TForml::Button3Click(TObject *Sender)
{
// от текущего дня до конца недели (до воскресенья)
TDateTime Present,
EndOfWeek;
Label2->Caption = "На этой неделе";
Present= Now(); // Now — возвращает текущую дату
// для доступа к StartOfWeek, EndOfWeek, YearOf и WeekOf
// надо подключить DateUtils.hpp (см. директивы tfinclude)
// **************************
EndOfWeek = StartOfAWeek(YearOf(Present),WeekOf(Present)+1);
Queryl->SQL->Strings[3] =
"(Date_F >= '"+
FormatDateTime("dd/mm/yyyy",Present)+"')
AND " + "(Date_F< '"+ FormatDateTime("dd/mm/yyyy",EndOfWeek)+"'}";
 Queryl->0pen();
if ( Queryl->RecordCount) {
DataSourcel->DataSet = Forml->Queryl;
 } else
ShowMessage("На эту неделю никаких дел не запланировано.");
 } 

В результате щелчка на кнопке Все в диалоговом окне программы должно быть выведено все содержимое базы данных. Базу данных представляет компонент Table1. Поэтому функция обработки события click на кнопке Все просто "переключает" источник данных на таблицу (листинг 5.2).

Листинг 5.2. Обработка события на кнопке Все

// Щелчок на кнопке Все
void__fastcall TForml::Button4Click(TObject *Sender)
{
// установить: источник данных — таблица
// таким образом, отобажается вся БД
Forml->DataSourcel->DataSet = Forml->Tablel;
Label2->Caption = "Все, что намечено сделать"; } 

Программа "Ежедневник" спроектирована таким образом, что при каждом ее запуске в диалоговом окне выводится текущая дата и список дел, запланированных на этот и ближайшие дни. Вывод даты и названия дня недели в поле Label выполняет функция обработки события onActivate (ее текст приведен в листинге 5.3). Эта же функция формирует критерий запроса к базе данных, обеспечивающий вывод списка задач, решение которых запланировано на сегодня (в день запуска программы) и на завтра. Если программа запускается в пятницу, субботу или воскресенье, то завтрашним днем считается понедельник. Такой подход позволяет сделать упреждающее напоминание, ведь, возможно, что пользователь не включит компьютер в выходные дни.

Листинг 5.3. Функция обработки события OnActivate

AnsiString stDay[7] = ("воскресенье","понедельник",
"вторник", "среда",
"четверг","пятница","суббота"};
AnsiString stMonth[12] = {"января","февраля","марта",
"апреля","мая","июня","июля",
 "августа","сентября",
"октября", "ноября","декабря"};
// активизация формы
void _fastcall TForml::FormActivate(TObject *Sender)
{
TDateTime Today, // сегодня
NextDay; // следующий день Сне обязательно завтра)
Word Year, Month, Day; // год, месяц, день
Today = Now ();
DecodeDate(Today, Year, Month, Day);
Labell->Caption = "Сегодня " + IntToStr(Day) +
 " " + stMonth[Month-l] + " " +
IntToStr(Year) + " года, " + stDay[DayOfWeek(Today) -1];
Label2->Caption = "Сегодня и ближайшие дни";
// вычислим следующий день
// если сегодня пятница, то, чтобы не забыть,
// что запланировано на понедельник, считаем, что следующий *
// день — понедельник
switch ( DayOfWeek(Today)) {
case 6 : NextDay = Today + 3; break; // сегодня пятница
case 7 : NextDay = Today + 2; break; // сегодня суббота
default : NextDay = Today + 1; break;
}
// запрос к базе данных: есть ли дела, запланированные
// на сегодня и на следующий день
Queryl->SQL->Strings[3] =
"(Date_F >= '"+ FormatDateTime("dd/mm/yyyy",Today)+"')
AND " + "(Date_F<= '"+
 FormatDateTime("dd/mm/yyyy",NextDay)+"')";
Queryl->Open();
DataSourcel->DataSet = Forml->Queryl;
if ( ! Queryl->RecordCount)
{
ShowMessage("На сегодня и ближайшие дни никаких дел не запланировано.");
}
}

Использование псевдонима для доступа к базе данных обеспечивает независимость программы от размещения данных в системе, позволяет размещать программу работы с данными и базу данных на разных дисках компьютера, в том числе и на сетевом. Вместе с тем для локальных баз данных типичным решением является размещение базы данных в отдельном подкаталоге того каталога, в котором находится программа работы с базой данных. Таким образом, программа работы с базой данных "знает", где находятся данные. При таком подходе можно отказаться от создания псевдонима при помощи Database Desktop и возложить задачу создания псевдонима на программу работы с базой данных. Очевидно, что такой подход облегчает администрирование базы данных.

В качестве иллюстрации сказанного в листинге 5.4 приведен вариант реализации функции OnActivate, которая создает псевдоним для базы данных organizer. Предполагается, что база данных находится в подкаталоге DATA того каталога, в котором находится выполняемый файл программы. Непосредственное создание псевдонима выполняет функция AddStandardAlias, которой в качестве параметра передается псевдоним и соответствующий ему каталог. Так как во время разработки программы нельзя знать, в каком каталоге будет размещена программа работы с базой данных и, следовательно, подкаталог базы данных, имя каталога определяется во время работы программы путем обращения к функциям Paramstrto) и ExtractFilePatch. Значение первой — полное имя выполняемого файла программы, второй — путь к этому файлу. Таким образом, процедуре AddStandardAlias передается полное имя каталога базы данных.

Листинг 5.4. Создание псевдонима во время работы программы

void__fastcall TForml::FormActivate(TObject *Sender)
{
TDateTime Today, // сегодня
NextDay; // следующий день (не обязательно завтра)
Word Year, Month, Day; // год, месяц, день
Today = Now (};
DecodeDate(Today, Year, Month, Day);
Labell->Caption = "Сегодня " + IntToStr(Day) +
 " " + stMonth[Month-l] + " " +
IntToStr(Year) + " года, " + stDay[DayOfWeek(Today) -1] ;
Label2->Caption = "Сегодня и ближайшие дни";
// вычислим следующий день
// если сегодня пятница, то, чтобы не забыть,
// что запланировано на понедельник, считаем, что следующий
// день — понедельник
switch ( DayOfWeek(Today)) {
case 6 : NextDay = Today + 3; break; // сегодня пятница
case 7 : NextDay = Today + 2; break; // сегодня суббота
default : NextDay = Today + 1; break;
}
#define DIN_ALIAS
// псевдоним доступа к БД создается динамически
// если псевдоним создан при помощи Database Desktop
// или BDE Administrator, директиву tfdefine DIN_ALIAS
//надо удалить ("закомментировать")
#ifdef DIN_ALIAS // псевдоним создается динамически
// создадим псевдоним для доступа к БД
Session->ConfigMode = cmSession;
Session->AddStandardAlias("organizer",
ExtractFilePath(ParamStr(0))+"DATA\\", "PARADOX");
 // база данных "Ежедневник"
// в формате Paradox
#endif
Forml->Tablel->Active = true;
 // открыть таблицу
// запрос к базе данных: есть ли дела, запланированные
 // на сегодня и завтра
Queryl->SQL->Strings[3] =
"(Date_F >= '"+
FormatDateTime("dd/mm/yyyy",Today)+"')
 AND " + "(Date_F <= '"+
FormatDateTime("dd/mm/yyyy",NextDay)+'")";
Queryl->0pen();
DataSourcel->DataSet = Forml->Queryl;
if ( ! Queryl->RecordCount)
(
ShowMessage("На сегодня и ближайшие дни
никаких дел не запланировано."); 
} }