учебники, программирование, основы, введение в,

 

Параметрические запросы

Формирование параметрических запросов
Параметры SQL-оператора
Параметром называется переменная, используемая в SQL-операторе.
Применение параметров позволяет формировать SQL-операторы непосредственно во время выполнения приложения. Так, при использовании многошагового интерфейса, при котором процесс компиляции и выполнения SQL-оператора происходит как последовательные действия, достаточно откомпилировать SQL-оператор с параметрами вместо явного указания значений полей таблицы базы данных, а затем многократно выполнять данный оператор с различными значениями параметров.
Например:
INSERT INTO TBL1 (F_ID, F2, F3) VALUES (?, ?, ?)
Параметры могут быть именованными и позиционными.
Позиционные параметры указываются символом вопросительный знак (?), называемым маркером параметров. При выполнении оператора вместо параметра в соответствующую позицию SQL-оператора приставляется значение параметра.
Согласно спецификации языка SQL маркеры параметров нельзя размещать в следующих местах SQL-оператора:

  • в списке полей оператора SELECT;
  • одновременно как оба операнда для бинарного оператора (например, оператора =), так как на этапе компиляции нельзя определить тип операндов, выступающих в роли параметров;
  • одновременно как первый и второй операнд для оператора BETWEEN (например, вместо SQL-оператора
  • SELECT title_id, f_sales FROM tbl1    

WHERE f_sales BETWEEN 4095 AND 12000
нельзя записать
SELECT title_id, f_sales FROM tbl1    
WHERE ? BETWEEN ? AND 12000 );

  • одновременно как первый и третий операнд для оператора BETWEEN;
  • одновременно как первый операнд и второй операнд для оператора IN (например, вместо SQL-оператора
  • SELECT f_ID, f_state FROM tbl1

WHERE f_state IN ('CA', 'CB')
нельзя записать
SELECT f_ID, f_state FROM tbl1
WHERE ? IN (?, ?)  );

  • как операнд унарного оператора + или -.

Определение параметров
Выполняемый SQL-оператор может содержать несколько параметров.
Для использования параметра его первоначально следует определить (выполнить связывание параметра). Определение параметра заключается в указании типов для значения (С-тип) и для поля таблицы (SQL-тип), а также для указания буфера, в котором будет содержаться значение параметра, или номера параметра - для его последующего запроса во время выполнения. Определение параметра реализуется функцией SQLBindParameter (вместо функции SQLSetParam в ODBC 1.0).
Функция SQLBindParameter имеет следующее формальное описание:
SQLRETURN SQLBindParameter(
SQLHSTMT     StatementHandle,
SQLUSMALLINT     ParameterNumber,
SQLSMALLINT     InputOutputType,
SQLSMALLINT     ValueType,
SQLSMALLINT     ParameterType,
SQLUINTEGER     ColumnSize,
SQLSMALLINT     DecimalDigits,
SQLPOINTER     ParameterValuePtr,
SQLINTEGER     BufferLength,
SQLINTEGER *     StrLen_or_IndPtr);
Параметр StatementHandle ([Input]) указывает дескриптор оператора, параметр ParameterNumber ([Input]) задает номер параметра (по мере их вхождения в SQL-оператор), начиная с 1.
Параметр InputOutputType ([Input]) определяет тип параметра.
Параметр ValueType ([Input]) определяет тип значения переменной (С-тип), из которой будет извлекаться значение, передаваемое в базу данных, а параметр ParameterType ([Input]) указывает тип параметра (SQL-тип поля таблицы базы данных).
Параметр ColumnSize ([Input]) определяет размер столбца или указывает выражение, соответствующее маркеру параметра, а параметр DecimalDigits ([Input]) определяет количество десятичных знаков в столбце или указывает выражение, соответствующее маркеру параметра. Получить размер столбца и количество десятичных знаков в столбце можно при помощи функции ODBC API SQLDescribeCol.
Параметр ParameterValuePtr ([Deferred Input]) является указателем на буфер для данных, передаваемых в качестве параметра. Длина этого буфера определяется параметром BufferLength ([Input/Output]), а указатель на буфер для длины параметра задается параметром StrLen_or_IndPtr ([Deferred Input]). Функция SQLBindParameter может возвращать следующие значения: SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

Передача параметров
Если перед выполнением функции SQLExecDirect значения параметров, используемых в запросе, не переданы на сервер, то функция возвращает код ответа SQL_NEED_DATA. Для передачи параметров в приложении могут использоваться функции SQLParamData и SQLPutData. Функция SQLParamData используется совместно с функцией SQLPutData для передачи значений параметров во время выполнения. Если функция SQLParamData возвращает значение SQL_NEED_DATA, то она также возвращает и номер параметра, для которого следует ввести значение. Передача значения параметра выполняется функцией SQLPutData.
Функция SQLParamData имеет следующее формальное описание:
SQLRETURN SQLParamData(
SQLHSTMT     StatementHandle,
SQLPOINTER *     ValuePtrPtr);
Параметр StatementHandle ([Input]) указывает дескриптор оператора, а параметр ValuePtrPtr ([Output]) указывает буфер, который был предназначен для хранения параметра функцией SQLBindParameter (указывается как значение параметра ParameterValuePtr).
Функция SQLPutData позволяет приложению передавать данные параметра или столбца во время выполнения. При этом данные могут передаваться по частям.
Функция SQLPutData имеет следующее формальное описание:
SQLRETURN SQLPutData(
SQLHSTMT     StatementHandle,
SQLPOINTER     DataPtr,
SQLINTEGER     StrLen_or_Ind);
Параметр StatementHandle ([Input]) указывает дескриптор оператора, параметр DataPtr ([Input]) определяет указатель буфера, в котором размещается значение параметра или столбец (значение соответствующего C-типа, указанного параметром ValueType функции SQLBindParameter или параметром TargetType функции SQLBindCol), а параметр StrLen_or_Ind ([Input]) определяет длину передаваемых данных *DataPtr.
Следующий пример иллюстрирует применение функций OBDC API для передачи параметров, используемых оператором INSERT. Этот оператор содержит два параметра - для полей F1_ID и F2_PIC. Для каждого параметра приложение вызывает метод SQLBindParameter, определяющий С-тип данных и SQL-тип поля.
#define MAX_DATA_LEN 1024
SQLINTEGER     cbF1_ID = 0, cbF2_PICParam, cbData;
SQLUINTEGER    sF1_ID;
szPhotoFile;
SQLPOINTER     pToken, InitValue;
SQLCHAR        Data[MAX_DATA_LEN];
SQLRETURN      retcode;
SQLHSTMT       hstmt;
// Компиляция параметрического запроса
retcode = SQLPrepare(hstmt,
"INSERT INTO TBL1 (F1_ID, F2_PIC)
VALUES (?, ?)", SQL_NTS);
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

   // Выполнение связывания параметров.
// Для 2 параметра передаем в ParameterValuePtr
// вместо адреса буфера номер параметра
SQLBindParameter(hstmt, 1,    // Для 1 параметра
SQL_PARAM_INPUT,
SQL_C_ULONG,
SQL_INTEGER,
0, 0,
&sF1_ID,
0,
&cbF1_ID);
SQLBindParameter(hstmt, 2,    // Для 2 параметра
SQL_PARAM_INPUT,
SQL_C_BINARY,
SQL_LONGVARBINARY,
0, 0,
(SQLPOINTER) 2, // Передаваемый номер
0,
&cbF2_PICParam);

   // Значения второго параметра будут передаваться
// во время выполнения.
// Длина параметра в макросе SQL_LEN_DATA_AT_EXEC
// равна 0. Это предполагает, что драйвер вернет
// значение "N" для типа SQL_NEED_LONG_DATA_LEN,
// указанного в функции SQLGetInfo.

   cbF2_PICParam = SQL_LEN_DATA_AT_EXEC(0);

   sF1_ID = MyGetNextID();   /* Запрос следующего значения поля  F1_ID таблицы TBL1 */

   retcode = SQLExecute(hstmt);

   /* Для параметров времени выполнения (data-at-execution parameters) вызывается
функция SQLParamData для получения номера параметра, установленного функцией 
SQLBindParameter. */
/* Вспомогательные функции  MyInitData и MyGetData формируют значение параметра*/
/* Функция SQLParamData завершает процесс обработки параметра */

   while (retcode == SQL_NEED_DATA) {
retcode = SQLParamData(hstmt, &pToken); // Запрос
// значений параметров во время выполнения
if (retcode == SQL_NEED_DATA) {        
MyInitData((SQLSMALLINT)pToken, InitValue);
while (MyGetData(InitValue,
(SQLSMALLINT)pToken, Data, &cbData))
SQLPutData(hstmt, Data, cbData);
}
}
}

VOID MyInitData (sParam, InitValue)
SQLPOINTER InitValue;
{
SQLCHAR szPhotoFile[MAX_FILE_NAME_LEN];

   /* Запрос у пользователя имени используемого BMP-файла, открытие этого файла и
возвращения дескриптора файла */

   MyPromptPhotoFileName(szPhotoFile);
MyOpenBMPFile(szPhotoFile, (FILE *)InitValue);
break;
}

BOOL MyGetData (InitValue, sParam, Data, cbData)
SQLPOINTER     InitValue;
SQLCHAR *      Data;
SQLINTEGER *   cbData;
BOOL           Done;

{
/* Функция MyGetNextBMPData возвращает следующую часть данных и количество
передаваемых байтов (не более, чем MAX_DATA_LEN). */
Done = MyGetNextBMPData((FILE *)InitValue, Data,
MAX_DATA_LEN, &cbData);
if (Done) { MyCloseBMPFile((FILE *)InitValue);
return (TRUE); }
return (FALSE);
}
Массивы параметров
Если значение атрибута дескриптора оператора SQL_ATTR_PARAMSET_SIZE больше 1 и SQL-оператор имеет хотя бы один маркер параметра, то функция SQLExecDirect будет выполняться последовательно для каждого значения параметра из массива, указанного параметром ParameterValuePointer функции SQLBindParameter.

Именованные параметры

Именованные параметры могут использоваться в том случае, когда в SQL-операторе выполняется вызов хранимой процедуры. Именованные параметры идентифицируются в соответствии с их именами, а не по порядку их расположения (как при позиционных параметрах). Именованные параметры, так же как и позиционные параметры, связываются с переменной посредством вызова функции ODBC API SQLBindParameter, но идентифицируются посредством поля SQL_DESC_NAME IPD-дескриптора (Implementation Parameter Descriptor). Именованные параметры также могут быть связаны с переменной при вызове функции SQLSetDescField или функции SQLSetDescRec.
Далее приведен пример применения именованных параметров, используемых при вызове предварительно созданной хранимой процедуры test с двумя параметрами

(CREATE PROCEDURE test @f_id int = 1, @f2 char(30) AS )

Первый параметр процедуры имеет значение, по умолчанию равное 1, а второй параметр @f2 обязательно должен быть указан при вызове процедуры. Параметр @f2 - это динамический параметр, называемый именованным параметром.

// Компилирование вызова хранимой процедуры 
SQLPrepare(hstmt, "{call test(?)}", SQL_NTS);
// Заполнение записи 1 для IPD-дескриптора 
SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, 
                 SQL_C_CHAR, SQL_CHAR,
                 30, 0, szF2, 0, &cbValue);
// Получение IPD-дескриптора и определение полей 
// SQL_DESC_NAMED и SQL_DESC_UNNAMED для записи  #1.
SQLGetStmtAttr(hstmt, SQL_ATTR_IMP_PARAM_DESC, 
               &hIpd, 0, 0);
SQLSetDescField(hIpd, 1, SQL_DESC_NAME, 
               "@f2", SQL_NTS);
SQLSetDescField(hIpd, 1, SQL_DESC_UNNAMED, 
                SQL_NAMED, 0);
// Если переменная szF2 была корректно 
// инициализирована, то можно выполнять 
// вызов хранимой процедуры
SQLExecute(hstmt);

 

 
На главную | Содержание | < Назад....Вперёд >
С вопросами и предложениями можно обращаться по nicivas@bk.ru. 2013 г.Яндекс.Метрика