
Перед тем как начинать писать программу создадим источник данных, с которым мы будем работать. Для этого в меню «Пуск» выбираем «Справка и поддержка». В появившемся окне напротив слова «Найти» пишем «ODBC» и нажимаем на кнопку со стрелкой.
Далее выбираем Использование компонента «Источник данных(ODBC)», затем «Источник данных (ODBC)».
В появившемся окне нажимаем кнопку «Добавить».
Далее выбираем «SQLServer» и нажимаем «Готово».
В следующем окне вводим имя источника данных и выбираем имя сервера, затем нажимаем «Далее».
В следующем окне мы оставляем все как есть и нажимаем «Далее».
Затем необходимо выбрать БД, если вы ничего не создавали, то по умолчанию используется БД master и нажимаем «Далее».
Следующее окно мы оставляем без изменения и нажимаем «Готово».
Нажимаем «OK».
Мы создали источник данных.
Создайте новый проект в Builder . Сохраните модуль формы в отдельном каталоге под именем uMyODBC, а проект - под именем ODBC. Имя формы myODBC.
Для нормальной работы с драйвером ODBC в наш проект необходимо подключить следующие библиотеки: odbc32.lib, odbccp32.lib. Для этого в главном меню выбираем «Project» / «Add to Project» и из списка файлов по очереди добавляем нужные нам библиотеки(библиотеки можно спросить у преподавателя или скачать самим из интернета).
Также в заголовочный файл модуля uMyODBC надо добавить следующие директивы препроцессора:
#include <sql.h>
и в uMyODBC.cpp:
#define WIN32
#include <sql.h>
#include <sqlext.h>
#include <odbcinst.h>
#include <sysutils.hpp>
#define SQL_API_SQLPARAMOPTION 33
#include <Grids.hpp>
В разделе «private» заголовочного файла модуля uMyODBC объявите структуру с двумя переменными типа String:
struct PolyaTab{
String pole1;
String pole2;
};
Для начала создадим несколько функций, которые помогут нам при работе с ODBC.
void Start(SQLHENV &hEnv,SQLHDBC &hDbc,TMemo * Memo) – создает идентификатор среды и соединения, инициализирует интерфейс ODBC, загружает драйвер базы данных и устанавливает соединение с источником данных.
Описание параметров для данной функции:
hEnv – идентификатор среды;
hDbc – идентификатор соединения;
DNS – имя источника данных;
Memo – многострочное поле для вывода сообщений о ходе работы программы.
Теперь создадим данную функцию. Для этого выделяем класс TmyODBC, нажимаем правой кнопкой мыши и в появившимся меню выбираем New Method …
Далее заполняем появившееся окно в соответствии с рисунком:
В редакторе кода напишем содержание функции:
void TmyODBC::Start(SQLHENV &hEnv,SQLHDBC &hDbc,char *DNS,TMemo * Memo)
{
char *USER = "SQL_NTS";
char *PASS = "SQL_NTS";
SQLRETURN Retcode;
Retcode=SQLAllocEnv(&hEnv);
if (Retcode == SQL_SUCCESS || Retcode == SQL_SUCCESS_WITH_INFO)
{
Memo->Lines->Add("Среда успешно создана");
Retcode = SQLAllocConnect(hEnv,&hDbc);
if(Retcode == SQL_SUCCESS || Retcode == SQL_SUCCESS_WITH_INFO)
{
Memo->Lines->Add("Соединение успешно создано");
Retcode=SQLConnect(hDbc,DNS,lstrlen(DNS),USER,lstrlen(USER),PASS,lstrlen(PASS));
if (Retcode == SQL_SUCCESS || Retcode == SQL_SUCCESS_WITH_INFO)
{
Memo->Lines->Add("Подконектилось успешно");
}else
Memo->Lines->Add("Подконектиться не получилось");
}
else
Memo->Lines->Add("Соединение не создано");
}
else
Memo->Lines->Add("Среда не создана");
}
void Stop(SQLHENV &hEnv,SQLHDBC &hDbc,TMemo * Memo) – закрывает соединение с источником данных, освобождает идентификатор соединения и всю связанную с ним память, освобождает идентификатор среды, а также всю назначенную ему память.
Параметры такие же, как и у предыдущей функции, только без DNS.
Теперь создадим данную функцию. Для этого выделяем класс TmyODBC, нажимаем правой кнопкой мыши и в появившимся меню выбираем New Method …
Далее заполняем появившееся окно в соответствии с рисунком:
В редакторе кода напишем содержание функции:
void TmyODBC::Stop(SQLHENV &hEnv,SQLHDBC &hDbc,TMemo * Memo)
{
SQLRETURN Retcode;
Retcode=SQLDisconnect(hDbc);
if (Retcode==SQL_SUCCESS)
Memo->Lines->Add("Дисконект успешно");
else
Memo->Lines->Add("Дисконект не успешно");
Retcode=SQLFreeConnect(hDbc);
if (Retcode==SQL_SUCCESS)
Memo->Lines->Add("Соединение удалилось успешно");
else
Memo->Lines->Add("Соединение не удалилось");
Retcode=SQLFreeEnv(hEnv);
if (Retcode==SQL_SUCCESS)
Memo->Lines->Add("Среда удалилась успешно");
else
Memo->Lines->Add("Среда не удалилась");
}
void SqlExecutePrepare(SQLHDBC hDbc,SQLHSTMT hStmt,String zapros,TMemo * Memo) – создает идентификатор оператора, выполняет SQL запрос и освобождает идентификатор оператора.
Описание параметров для данной функции:
hDbc – идентификатор соединения;
hStmt – идентификатор оператора;
zapros – SQL запрос;
Memo – многострочное поле для вывода сообщений о ходе работы программы.
Теперь создадим данную функцию. Для этого выделяем класс TmyODBC, нажимаем правой кнопкой мыши и в появившимся меню выбираем New Method …
Далее заполняем появившееся окно в соответствии с рисунком:
В редакторе кода напишем содержание функции:
void TmyODBC::SqlExecutePrepare(SQLHDBC hDbc,SQLHSTMT hStmt,String zapros,TMemo * Memo)
{
SQLRETURN Retcode;
Retcode=SQLAllocStmt(hDbc,&hStmt);
if (Retcode==SQL_SUCCESS)
{
Retcode=SQLPrepare(hStmt,zapros.c_str(),lstrlen(zapros.c_str()));
if (Retcode==SQL_SUCCESS)
{
Retcode=SQLExecute(hStmt);
if (Retcode==SQL_SUCCESS)
{
Memo->Lines->Add("Запрос : ");
Memo->Lines->Add(zapros);
Memo->Lines->Add("успешно выполнен");
}
else
{
Memo->Lines->Add("Запрос : ");
Memo->Lines->Add(zapros);
Memo->Lines->Add("не выполнен");
}
}
}
SQLFreeStmt(hStmt,SQL_CLOSE);
}
void SelectGetData(SQLHDBC hDbc,SQLHSTMT hStmt,String zapros,TMemo * Memo,TStringGrid *StringGrid) –выполняет выборку всех данных из таблицы для 9 столбцов и выводит результат в String Grid.
Описание параметров для данной функции:
hDbc – идентификатор соединения;
hStmt – идентификатор оператора;
zapros – SQL запрос;
Memo – многострочное поле для вывода сообщений о ходе работы программы;
StringGrid – таблица, содержащая строки.
Теперь создадим данную функцию. Для этого выделяем класс TmyODBC, нажимаем правой кнопкой мыши и в появившимся меню выбираем New Method …
Далее заполняем появившееся окно в соответствии с рисунком:
В редакторе кода напишем содержание функции:
void TmyODBC::SelectGetData(SQLHDBC hDbc,SQLHSTMT hStmt,String zapros,TMemo * Memo,TStringGrid *StringGrid)
{
int R, C;
for (R = 1; R < StringGrid->RowCount; R++)
{
for (C = 0; C < StringGrid->ColCount; C++)
StringGrid->Cells[C][R] = "";
}
StringGrid->RowCount=2;
StringGrid->ColCount=9;
SQLRETURN Retcode;
int j=1;
Retcode = SQLAllocStmt(hDbc,&hStmt);
SQLCHAR sqf1[50],sqf2[50],sqf4[50],sqf8[50],sqf9[50];
SQLCHAR sqf3;
SQLSMALLINT sqf5;
SQLREAL sqf6,sqf7;
SQLINTEGER ValueLenOrInd1 ,ValueLenOrInd2,ValueLenOrInd3,ValueLenOrInd4,ValueLenOrInd5,ValueLenOrInd6,ValueLenOrInd7,ValueLenOrInd8,ValueLenOrInd9;
Retcode = SQLExecDirect(hStmt, zapros.c_str(), SQL_NTS);
if (Retcode == SQL_SUCCESS) {
while (TRUE) {
Retcode = SQLFetch(hStmt);
if (Retcode == SQL_ERROR || Retcode == SQL_SUCCESS_WITH_INFO) {
}
if (Retcode == SQL_SUCCESS || Retcode == SQL_SUCCESS_WITH_INFO){
SQLGetData(hStmt, 1, SQL_C_CHAR, &sqf1, 50, &ValueLenOrInd1);
SQLGetData(hStmt, 2, SQL_C_CHAR, &sqf2, 50, &ValueLenOrInd2);
SQLGetData(hStmt, 3, SQL_C_DEFAULT, &sqf3, sizeof(sqf3),&ValueLenOrInd3);
SQLGetData(hStmt, 4, SQL_C_CHAR, &sqf4, 50, &ValueLenOrInd4);
SQLGetData(hStmt, 5, SQL_C_DEFAULT, &sqf5, sizeof(sqf5),&ValueLenOrInd5);
SQLGetData(hStmt, 6, SQL_C_FLOAT, &sqf6, sizeof(sqf6),&ValueLenOrInd6);
SQLGetData(hStmt, 7, SQL_C_FLOAT, &sqf7, sizeof(sqf7),&ValueLenOrInd7);
SQLGetData(hStmt, 8, SQL_C_CHAR, &sqf8, 50,&ValueLenOrInd8);
SQLGetData(hStmt, 9, SQL_C_CHAR, &sqf9, 50,&ValueLenOrInd9);
AnsiString a1,a2,a4,a5,a6,a7,a8,a9,a10;
a1.printf("%s",sqf1);
a2.printf("%s",sqf2);
a4.printf("%s",sqf4);
a5=IntToStr(sqf5);
a6=FloatToStr(sqf6);
a7=FloatToStr(sqf7);
a8.printf("%s",sqf8);
a9.printf("%s",sqf9);
Memo->Lines->Add("Из таблицы postov "+a1+" "+a2+ " "+sqf3+" "+a4+" "+a5+" "+a6+" "+a7+" "+a8+" "+a9);
StringGrid->Cells[0][j]=a1;
StringGrid->Cells[1][j]=a2;
StringGrid->Cells[2][j]=sqf3;
StringGrid->Cells[3][j]=a4;
StringGrid->Cells[4][j]=a5;
StringGrid->Cells[5][j]=a6;
StringGrid->Cells[6][j]=a7;
StringGrid->Cells[7][j]=a8;
StringGrid->Cells[8][j]=a9;
j++;
StringGrid->RowCount++;
} else {
break;
}
}
}
StringGrid->RowCount--;
SQLFreeStmt(hStmt,SQL_CLOSE);
}
TmyODBC::PolyaTab TmyODBC::SqlExecRetS(SQLHDBC hDbc,SQLHSTMT hStmt,String zapros,TMemo * Memo,TStringGrid *StringGrid) – предназначена для работы с курсором, возвращает структуру содержащую 2 переменные типа String - поля таблицы, ее первичный ключ.
Описание параметров для данной функции:
hDbc – идентификатор соединения;
hStmt – идентификатор оператора;
zapros – SQL запрос;
Memo – многострочное поле для вывода сообщений о ходе работы программы;
StringGrid – таблица, содержащая строки.
Теперь создадим данную функцию. Для этого выделяем класс TmyODBC, нажимаем правой кнопкой мыши и в появившимся меню выбираем New Method …
Далее заполняем появившееся окно в соответствии с рисунком:
В редакторе кода напишем содержание функции:
TmyODBC::PolyaTab TmyODBC::SqlExecRetS(SQLHDBC hDbc,SQLHSTMT hStmt,String zapros,TMemo * Memo,TStringGrid *StringGrid)
{
SQLRETURN Retcode;
PolyaTab s;
int j=1;
Retcode = SQLAllocStmt(hDbc,&hStmt);
SQLCHAR sqf1[50],sqf2[50],sqf4[50],sqf8[50],sqf9[50];
SQLCHAR sqf3;
SQLSMALLINT sqf5;
SQLREAL sqf6,sqf7;
SQLINTEGER ValueLenOrInd1 ,ValueLenOrInd2,ValueLenOrInd3,ValueLenOrInd4,ValueLenOrInd5,ValueLenOrInd6,ValueLenOrInd7,ValueLenOrInd8,ValueLenOrInd9;
Retcode = SQLExecDirect(hStmt, zapros.c_str(), SQL_NTS);
if (Retcode == SQL_SUCCESS) {
Memo->Lines->Add("Запрос "+zapros+" успешно выполнен");
while (TRUE) {
Retcode = SQLFetch(hStmt);
if (Retcode == SQL_ERROR || Retcode == SQL_SUCCESS_WITH_INFO) {
}
if (Retcode == SQL_SUCCESS || Retcode == SQL_SUCCESS_WITH_INFO){
SQLGetData(hStmt, 1, SQL_C_CHAR, &sqf1, 50, &ValueLenOrInd1);
SQLGetData(hStmt, 2, SQL_C_CHAR, &sqf2, 50, &ValueLenOrInd2);
AnsiString a1,a2,a4,a5,a6,a7,a8,a9,a10;
a1.printf("%s",sqf1);
a2.printf("%s",sqf2);
s.pole1=a1;
s.pole2=a2;
Memo->Lines->Add("Из таблицы postov SqlExecRetS "+s.pole1+" "+s.pole2);
j++;
} else {
break;
}
}
} else Memo->Lines->Add("Запрос "+zapros+" не выполнен");
SQLFreeStmt(hStmt,SQL_CLOSE);
return s;
}
void TmyODBC::SetCur(TmyODBC::PolyaTab h,TStringGrid * StringGrid) – устанавливает курсор таблицы String Grid на строку у которой значение первых двух столбцов (значение первичного ключа) совпадает со значением переменных структуры h.
Описание параметров для данной функции:
h – структура, содержащая две переменных типа String;
StringGrid – таблица, содержащая строки.
Теперь создадим данную функцию. Для этого выделяем класс TmyODBC, нажимаем правой кнопкой мыши и в появившимся меню выбираем New Method …
Далее заполняем появившееся окно в соответствии с рисунком:
В редакторе кода напишем содержание функции:
void TmyODBC::SetCur(TmyODBC::PolyaTab h,TStringGrid * StringGrid)
{
int nomer;
int count=StringGrid->RowCount;
for (int i=1;i<=count;i++){
if (StringGrid->Cells[0][i]==h.pole1 && StringGrid->Cells[1][i]==h.pole2)
nomer=i;
}
if (nomer<count)
StringGrid->Row=nomer;
}
Теперь добавим в проект новую форму. Сохраните модуль формы в том же каталоге, что и проект под именем uMainForm. Установите свойства главной формы в следующие значения:
Name – MainForm;
Caption - Выполнение операторов SQL в ODBC;
Position – poScreenCenter.
Эта форма должна будет появляться на экране при запуске программы. Для этого выберете в главном меню «Project»/«Options» закладка «Forms», в строке «Main form» впишите MainForm , далее перенесите myODBC из «Auto-create» forms в «Available forms», чтобы она не появлялась на экране при запуске программы.
Еще нам нужно подключить к новому модулю модуль uMyODBC. Для этого в заголовочном файле модуля uMainForm надо добавить следующую директиву препроцессора :
#include "uMyODBC.h". Теперь в разделе private добавляем следующее:
TmyODBC * MyODBC;
Также в заголовочный файл модуля uMainForm надо добавить следующие директивы препроцессора:
#include <sql.h>
и в uMainForm.cpp:
#define WIN32
#include <sql.h>
#include <sqlext.h>
#include <odbcinst.h>
#include <sysutils.hpp>
#define SQL_API_SQLPARAMOPTION 33
В разделе «private» заголовочного файла модуля uMyODBC объявите следующие переменные:
SQLHENV hEnv;
SQLHDBC hDbc;
SQLHSTMT hStmt;
SQLRETURN Retcode;
Int SelectedStroka;
На главную форму перенесите следующие компоненты:
StatusBar со страницы Win32;
Panel со страницы Standard.
Установите свойства компонента TPanel в следующие значения:
Align – alBottom;
Name – Panel;
Caption - .
На панельку со страницы Standard перенесите 12 компонентов Button.Установите их свойства в следующие значения:
1)Name – buStart;
Caption – Пуск;
2)Name – buSelect;
Caption – Выборка;
3) Name – buFirst;
Caption – Первая;
4)Name – buPrior;
Caption – Предыдущая;
5) Name – buNext;
Caption – Следующая;
6)Name – buLast;
Caption – Последняя;
7) Name – buDelete;
Caption – Удалить;
8)Name – buUpdate;
Caption – Модифицировать;
9)Name – buAdd;
Caption – Добавить;
10) Name – buInsert;
Caption – Вставить.
11) Name – buStop;
Caption – Стоп;
12)Name – buExit;
Caption – Выход;
На главную форму перенесите Memo со страницы Standard. Этот компонент будет нужен для отображения хода работы программы, что-то вроде журнала сообщений.
Установите свойства компонента Memo в следующие значения:
Align – alBottom;
Name – Memo, а также удалите все строки в свойстве Lines.
На главную форму перенесите еще одну панельку Panel со страницы Standard.
Установите свойства компонента Panel в следующие значения:
Align – alTop;
Name – Panel1;
Caption - .
На панельку со страницы Standard перенесите 1 компонент Button и 1 компонент ComboBox.Установите их свойства в следующие значения:
А)Для кнопки:
1)Name – buExec;
Caption – Выполнить ;
Б)Для ComboBox:
Name – cbZapros.
Добавим в cbZapros несколько запросов, которые нам понадобятся в дальнейшем. Для этого в свойстве Items этого компонента надо нажать на кнопку с тремя точками. В появившемся окне мы добавляем следующие строчки:
CREATE TABLE postov(p_name_firmy_postavchika VARCHAR(50) NOT NULL , p_name_firmy_potrebitelya VARCHAR(50) NOT NULL CONSTRAINT PK PRIMARY KEY (p_name_firmy_postavchika,p_name_firmy_potrebitelya) , p_tovarniy_kredit BIT , p_name_tovara VARCHAR(50) , p_kol_vo_ed_tovara SMALLINT CHECK (p_kol_vo_ed_tovara>0 AND p_kol_vo_ed_tovara<100), p_ves_ed_tovara FLOAT , p_cena_ed_tovara FLOAT , p_plategnye_rekvizity VARCHAR(50), p_data_otgruzky VARCHAR(50));
INSERT INTO postov (p_name_firmy_postavchika,p_name_firmy_potrebitelya, p_tovarniy_kredit,p_name_tovara,p_kol_vo_ed_tovara,p_ves_ed_tovara,p_cena_ed_tovara, p_plategnye_rekvizity,p_data_otgruzky)VALUES('ИВТ','АЛМАЗ',1,'Холодильник',90,100.5,60000,'Кураева 1а,1212232123','10/10/08');
INSERT INTO postov (p_name_firmy_postavchika,p_name_firmy_potrebitelya, p_tovarniy_kredit,p_name_tovara,p_kol_vo_ed_tovara,p_ves_ed_tovara,p_cena_ed_tovara, p_plategnye_rekvizity,p_data_otgruzky)VALUES('ИВТ','КРИСТАЛ',1,'Утюг',80,3.3,20000,'Кураева 1а,1212232123','10/10/08');
INSERT INTO postov (p_name_firmy_postavchika,p_name_firmy_potrebitelya, p_tovarniy_kredit,p_name_tovara,p_kol_vo_ed_tovara,p_ves_ed_tovara,p_cena_ed_tovara, p_plategnye_rekvizity,p_data_otgruzky)VALUES('ИВТ','РУБИН',0,'Пылесос',50,7.4,30000,'Кураева 1а,1212232123','10/10/08');
drop table postov
Необходимо, чтобы каждый запрос был на отдельной строчке.
Первая строчка и последняя – это запрос на создание и удаление таблицы, все остальные для вставки данных в таблицу.
На главную форму перенесите StringGrid со страницы Additional.
Установите свойства компонента StringGrid в следующие значения:
Align – alClient;
Name – StringGrid1;
Options/goRowSizing – true;
Options/goColSizing – true;
Options/goEditing – true;
Options/goRowSelect – true;
FixedCols – 0;
ColCount – 2;
RowCount – 2;
DefaultColWidth – 130.
Теперь переходим к написанию обработчиков событий. Выделите мышкой кнопку «Пуск», перейдите на страничку Events инспектора объектов и дважды щелкните по событию OnClick. В редакторе кода откроется пустой обработчик этого события, в который необходимо ввести операторы:
void __fastcall TMainForm::buStartClick(TObject *Sender)
{
MyODBC->Start(hEnv,hDbc,"my_source",Memo1);
buStart->Enabled=false;
buSelect->Enabled=true;
buFirst->Enabled=true;
buPrior->Enabled=true;
buNext->Enabled=true;
buLast->Enabled=true;
buDelete->Enabled=true;
buUpdate->Enabled=true;
buAdd->Enabled=true;
buInsert->Enabled=true;
buStop->Enabled=true;
buExit->Enabled=false;
buExec->Enabled=true;
}
Выделите мышкой кнопку «Стоп», перейдите на страничку Events инспектора объектов и дважды щелкните по событию OnClick. В редакторе кода откроется пустой обработчик этого события, в который необходимо ввести операторы:
void __fastcall TMainForm::buStopClick(TObject *Sender)
{
cbZapros->Text="";
int R, C;
for (R = 0; R < StringGrid1->RowCount; R++)
{
for (C = 0; C < StringGrid1->ColCount; C++)
StringGrid1->Cells[C][R] = "";
}
StringGrid1->RowCount=2;
StringGrid1->ColCount=2;
MyODBC->Stop(hEnv,hDbc,Memo1);
buStart->Enabled=true;
buSelect->Enabled=false;
buFirst->Enabled=false;
buPrior->Enabled=false;
buNext->Enabled=false;
buLast->Enabled=false;
buDelete->Enabled=false;
buUpdate->Enabled=false;
buAdd->Enabled=false;
buInsert->Enabled=false;
buStop->Enabled=false;
buExit->Enabled=true;
buExec->Enabled=false;
}
Выделите мышкой кнопку «Выход», перейдите на страничку Events инспектора объектов и дважды щелкните по событию OnClick. В редакторе кода откроется пустой обработчик этого события, в который необходимо ввести операторы:
void __fastcall TMainForm::buExitClick(TObject *Sender)
{
Close();
}
При нажатие на кнопку «Выполнить» будет выполняться sql запрос, который пользователь выберет в ComboBoxe. Выделите мышкой кнопку «Выполнить», перейдите на страничку Events инспектора объектов и дважды щелкните по событию OnClick. В редакторе кода откроется пустой обработчик этого события, в который необходимо ввести операторы:
void __fastcall TMainForm:: buExecClick (TObject *Sender)
{
MyODBC->SqlExecutePrepare(hDbc,hStmt,cbZapros->Text,Memo1);
}
Добавим в класс TMainForm новый метод. Для этого выделяем класс TMainForm, нажимаем правой кнопкой мыши и в появившимся меню выбираем New Method …
Далее заполняем появившееся окно в соответствии с рисунком:
В редакторе кода напишем содержание функции:
void TMainForm::Select()
{
MyODBC->SqlExecutePrepare(hDbc,hStmt,"close mycursor",Memo1);
MyODBC->SelectGetData(hDbc,hStmt,"select * from postov",Memo1,StringGrid1);
MyODBC->SqlExecutePrepare(hDbc,hStmt,"DECLARE mycursor SCROLL CURSOR for select * from postov",Memo1);
MyODBC->SqlExecutePrepare(hDbc,hStmt,"open mycursor",Memo1);
MyODBC->SqlExecutePrepare(hDbc,hStmt,"FETCH first from mycursor",Memo1);
}
Выделите мышкой кнопку «Выборка», перейдите на страничку Events инспектора объектов и дважды щелкните по событию OnClick. В редакторе кода откроется пустой обработчик этого события, в который необходимо ввести операторы: