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

 

Блочная выборка данных

Реализация блочной выборки строк
При использовании перемещаемого курсора для изменения текущей позиции курсора и выборки строк используется функция SQLFetchScroll. Эта функция позволяет реализовывать:

  • относительный скроллинг - перемещение по результирующему набору в двух направлениях и на любое число строк;
  • абсолютный скроллинг - перемещение на первую или на последнюю строку, или на строку с указанным номером.

Функция SQLFetchScroll выполняет выборку набора строк из сформированного результирующего набора и возвращает данные для всех связанных столбцов. Наборы строк (rowset) могут быть указаны как через абсолютное или относительное позиционирование, так и посредством закладок (bookmark). В версии ODBC 2.x для этих целей использовалась функция SQLExtendedFetch.
Функция SQLFetchScroll имеет следующее формальное описание:
SQLRETURN SQLFetchScroll(
SQLHSTMT     StatementHandle,
SQLSMALLINT     FetchOrientation,
SQLINTEGER     FetchOffset);
Параметр StatementHandle ([Input]) указывает дескриптор оператора.
Перемещение курсора определяется типом выборки, указывается параметром FetchOrientation ([Input]) и может принимать следующие значения:

  • SQL_FETCH_NEXT - переход к следующей строке (относительный скроллинг);
  • SQL_FETCH_PRIOR - переход к предыдущей строке (относительный скроллинг);
  • SQL_FETCH_FIRST - переход к первой строке (абсолютный скроллинг);
  • SQL_FETCH_LAST - переход к последней строке (абсолютный скроллинг);
  • SQL_FETCH_ABSOLUTE - переход к строке с указанным номером (абсолютный скроллинг);
  • SQL_FETCH_RELATIVE - перемещение вперед или назад на указанное количество строк (относительный скроллинг);
  • SQL_FETCH_BOOKMARK - переход к строке по закладке (абсолютный скроллинг).

Количество строк, на которые выполняется перемещение курсора и номер абсолютной позиции, указывается параметром FetchOffset ([Input]).
Параметры FetchOrientation и FetchOffset функции SQLFetchScroll совместно определяют набор строк, который будет извлечен из результирующего набора. На следующей схеме показан механизм выборки строк при позиционировании на следующую, предыдущую, первую или последнюю строку.
Механизм выборки строк при помощи функции SQLFetchScroll также позволяет реализовывать позиционирование по абсолютному указанному номеру, позиционирование со смещением на заданное число строк или позиционирование посредством закладки. Эти механизмы отображены на следующей схеме.
Функция SQLFetchScroll выполняет позиционирование курсора на указанную строку результирующего набора и возвращает набор строк, начиная с установленной позиции курсора. Если требуемый набор строк выходит за нижнюю границу результирующего набора, то возвращается существующая часть требуемого набора строк. А при выходе за верхнюю границу, как правило, возвращается набор строк требуемого размера, начиная с первой строки результирующего набора.
Иногда требуется выполнить позиционирование курсора без извлечения данных - например, для проверки существования строки или для получения закладки строки. В этом случае следует установить режим выполнения SQL_RD_OFF (без чтения). Такой режим устанавливается назначением атрибуту оператора SQL_ATTR_RETRIEVE_DATA значения SQL_RD_OFF. Отметим, что если существует переменная, связанная со столбцом закладок, то она всегда обновляется вне зависимости от того, какой режим установлен.
После того как набор строк будет извлечен, для позиционирования в нем конкретной строки или извлечения строки можно использовать функцию SQLSetPos.

Связывание столбцов, используемых с блочным курсором

При использовании блочного курсора за один вызов функции может возвращаться несколько строк. Поэтому с каждым столбцом должна связываться не просто переменная соответствующего типа, а массив. Такой массив обычно называется буфером набора строк (rowset buffer).
Возможно два типа связывания:

  • связывание по столбцу (column-wise binding), при котором с каждым столбцом связывается отдельный массив (структура данных, содержащая элементы одного типа);
  • связывание по строке (row-wise binding), при котором с каждой строкой связывается отдельный массив (структура данных, типы элементов которой соответствуют типам столбцов строки набора данных).

Для выполнения любого типа связывания используется функция ODBC API SQLBindCol. При этом тип связывания определяется атрибутом SQL_ATTR_ROW_BIND_TYPE. В случае использования блочного курсора со связыванием по строке или по столбцу, функции SQLBindCol в качестве параметра вместо адреса простой переменной передается адрес массива.

Связывание по столбцу

При использовании связывания по столбцу с каждым столбцом может быть связано от одного до трех массивов: первый массив - для извлекаемых значений, второй - для длины / индикатора буферов, третий - для индикатора буферов (если индикаторы и длина хранятся по отдельности). Каждый массив должен содержать число элементов, равное числу строк в извлекаемом наборе строк.
Хранятся ли по отдельности индикаторы и значения длины, определяется установкой дескрипторов полей SQL_DESC_INDICATOR_PTR и SQL_DESC_OCTET_LENGTH_PTR.
На следующем рисунке приведена схема связывания по столбцам.
Следующий пример иллюстрирует применение связывания по столбцам для набора строк, состоящего из трех столбцов:

#define ROW_ARRAY_SIZE 10      // Кол-во строк  
                               // в наборе строк 
 
SQLUINTEGER    ID1Array[ROW_ARRAY_SIZE], 
               NumRowsFetched;
SQLCHAR        SalArray[ROW_ARRAY_SIZE][11],
               StatusArray[ROW_ARRAY_SIZE][7];
SQLINTEGER     ID1IndArray[ROW_ARRAY_SIZE],
               SalLenOrIndArray[ROW_ARRAY_SIZE],
               StatusLenOrIndArray[ROW_ARRAY_SIZE];
SQLUSMALLINT   RowStatusArray[ROW_ARRAY_SIZE], i;
SQLRETURN      rc;
SQLHSTMT       hstmt;
 
// Устанавливаем атрибут оператора // SQL_ATTR_ROW_BIND_TYPE для использования связывания  
// по столбцам 
SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_BIND_TYPE, 
                      SQL_BIND_BY_COLUMN, 0);
// Размер набора строк задаем атрибутом оператора 
// SQL_ATTR_ROW_ARRAY_SIZE 
SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, 
                      ROW_ARRAY_SIZE, 0);
// Устанавливаем атрибут оператора 
// SQL_ATTR_ROW_STATUS_PTR для определения массива 
// состояний строк
SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_STATUS_PTR, 
                      RowStatusArray, 0);
// Устанавливаем атрибут оператора 
// SQL_ATTR_ROWS_FETCHED_PTR для указания на 
// cRowsFetched
SQLSetStmtAttr(hstmt, SQL_ATTR_ROWS_FETCHED_PTR, 
                      &NumRowsFetched, 0);
 
// Связываем массивы со столбцами ID1, Sal и Status
SQLBindCol(hstmt, 1, SQL_C_ULONG, 
           ID1Array, 0, 
           ID1IndArray);
SQLBindCol(hstmt, 2, SQL_C_CHAR, 
           SalArray, 
           sizeof(SalArray[0]),
            SalLenOrIndArray);
SQLBindCol(hstmt, 3, SQL_C_CHAR, 
           StatusArray, 
           sizeof(StatusArray[0]),
           StatusLenOrIndArray);
 
// Выполняем SQL-оператор SELECT для создания  
// результирующего набора 
SQLExecDirect(hstmt, 
              "SELECT ID1, Sal, Status FROM TBL1", 
              SQL_NTS);
 
// Выполняем блочную выборку из результирующего набора
// В переменной NumRowsFetched возвращается число 
// в действительности выбранных строк
while ((rc = SQLFetchScroll(hstmt,SQL_FETCH_NEXT,0)) 
                                   != SQL_NO_DATA) 
{
   for (i = 0; i < NumRowsFetched; i++) {
 
// Отображаем только успешно извлеченные строки (если 
// код ответа (rc) равен SQL_SUCCESS_WITH_INFO или 
// SQL_ERROR, то строку не выводим.)
 
      if ((RowStatusArray[i] == SQL_ROW_SUCCESS) ||
     (RowStatusArray[i] == SQL_ROW_SUCCESS_WITH_INFO))
{
         if (ID1IndArray[i] == SQL_NULL_DATA)
                       printf(" NULL      ");
         else          printf("%d\t", ID1Array[i]);
         if (SalLenOrIndArray[i] == SQL_NULL_DATA)
                       printf(" NULL      ");
         else          printf("%s\t", SalArray[i]);
         if (StatusLenOrIndArray[i] == SQL_NULL_DATA)
                       printf(" NULL\n");
         else          printf("%s\n", StatusArray[i]);
      }
   }
}
// Закрываем курсор
SQLCloseCursor(hstmt);

Связывание по строкам

При использовании связывания по строкам определяется структура, содержащая от одного до трех элементов для каждого столбца извлекаемых данных. Первый элемент предназначается для извлекаемых данных, второй - для длины / индикатора буфера, третий - для индикатора буфера при раздельном сохранении значений длины и индикатора (что определяется дескрипторами полей SQL_DESC_INDICATOR_PTR и SQL_DESC_OCTET_LENGTH_PTR).
Массив таких структур должен содержать количество элементов, равное числу строк в извлекаемом наборе строк.
Размер структуры (число строк) указывается атрибутом оператора SQL_ATTR_ROW_BIND_TYPE. При связывании используются адреса каждого члена первого элемента массива. Так, адрес конкретного значения из набора строк может быть вычислен следующим образом (нумерация строк с 1):

Адрес = Адрес_связывания + 
        ((Номер_строки - 1) * Размер_структуры)

На следующем рисунке приведена схема связывания по строкам.
Следующий пример иллюстрирует применение связывания по строкам для набора строк, состоящего из трех столбцов.

#define ROW_ARRAY_SIZE 10
 
// Определяем структуру TBL_INFO и создаем массив 
// структур, содержащий 10 элементов
typedef struct {
   SQLUINTEGER   ID1;    // Для значения 1 столбца
   SQLINTEGER    ID1Ind;   // Для длины/индикатора
   SQLCHAR       Sal[11];   // Для значения 2 столбца
   SQLINTEGER    SalLenOrInd;
   SQLCHAR       Status[7];  // Для значения 3 столбца 
   SQLINTEGER    StatusLenOrInd;
} ORDERINFO;
TBL_INFO TBL_Array[ROW_ARRAY_SIZE]; // Массив структур 
 
SQLUINTEGER    NumRowsFetched;
SQLUSMALLINT   RowStatusArray[ROW_ARRAY_SIZE], i;
SQLRETURN      rc;
SQLHSTMT       hstmt;
 
// Определяем размер структуры, используя атрибут 
//оператора SQL_ATTR_ROW_BIND_TYPE, и одновременно 
// устанавливаем тип связывания по строкам
SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_BIND_TYPE, 
                      sizeof(TBL_INFO), 0);
 
// Используя атрибут оператора SQL_ATTR_ROW_ARRAY_SIZE
// устанавливаем количество строк в извлекаемом наборе 
// строк 
SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, 
                      ROW_ARRAY_SIZE, 0);
 
// Используя атрибут оператора SQL_ATTR_ROW_STATUS_PTR 
// определяем массив состояния строк 
SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_STATUS_PTR, 
                      RowStatusArray, 0);
// Устанавливаем атрибут оператора  
// SQL_ATTR_ROWS_FETCHED_PTR для указания на  
// NumRowsFetched
SQLSetStmtAttr(hstmt, SQL_ATTR_ROWS_FETCHED_PTR, 
                      &NumRowsFetched, 0);
 
// Связываем поля структуры первого элемента массива 
// со столбцами ID1, Sal и Status 
SQLBindCol(hstmt, 1, SQL_C_ULONG, 
                      &TBL_Array[0].ID1, 
                      0, 
                      &TBL_Array[0].ID1Ind);
SQLBindCol(hstmt, 2, SQL_C_CHAR, 
                      TBL_Array[0].Sal,
                      sizeof(TBL_Array[0].Sal),
                      &TBL_Array[0].SalLenOrInd);
SQLBindCol(hstmt, 3, SQL_C_CHAR, 
                      TBL_Array[0].Status,
                      sizeof(TBL_Array[0].Status), 
                      &TBL_Array[0].StatusLenOrInd);
 
// Выполняем SQL-оператор SELECT для формирования  
// результирующего набора 
SQLExecDirect(hstmt, 
      "SELECT ID1, Sal, Status FROM TBL1", SQL_NTS);
 
// Используя блочный курсор, извлекаем установленное 
//число строк 
while ((rc = SQLFetchScroll(hstmt,SQL_FETCH_NEXT,0)) 
                                       != SQL_NO_DATA) 
{
// Переменная NumRowsFetched содержит число  
// в действительности извлеченных строк
   for (i = 0; i < NumRowsFetched; i++) 
  {
    if (RowStatusArray[i] == SQL_ROW_SUCCESS|| 
         RowStatusArray[i] == 
         SQL_ROW_SUCCESS_WITH_INFO) {
     if (TBL_Array[i].ID1Ind == SQL_NULL_DATA)
              std::cout<<" NULL      ";
     else     std::cout<< TBL_Array[i].ID1;
     if (TBL_Array[i].SalLenOrInd == SQL_NULL_DATA)
              std::cout<< " NULL      ";
     else     std::cout<< TBL_Array[i].Sal;
     if (TBL_Array[i].StatusLenOrInd == SQL_NULL_DATA)
              std::cout<< " NULL\n";
     else     std::cout<< TBL_Array[i].Status;
    }
   }
}
// Закрываем курсор
SQLCloseCursor(hstmt);
 
На главную | Содержание | < Назад....Вперёд >
С вопросами и предложениями можно обращаться по nicivas@bk.ru. 2013 г.Яндекс.Метрика