Содержание


Введение в методы доступа к данным во встроенном SQL

Comments

Предварительные сведения

Компилятор IBM XL C/C++ для z/OS поддерживает использование встроенных SQL-операторов в программах, написанных на C/C++. В данной статье предполагается использование сопроцессора XL C/C++ DB2. В статье описываются различные методы взаимодействия с SQL-данными во встроенной программе SQL XL C/C++, работающей на z/OS.

Извлечение данных из SQL с помощью хост-переменных

Самый простой метод извлечения данных из SQL-таблицы – это использование хост-переменных. Хост-переменные позволяют программе на C/C++ взаимодействовать с DB2.

Пример: хост-переменные

Примечание. В примерах статьи используется таблица студентов (см. листинг 1).

Листинг 1. Таблица студентов
EXEC SQL CREATE TABLE Students                                              
(
   STUDENTNO INT NOT NULL,
   FIRSTNAME VARCHAR(12) NOT NULL,
   LASTNAME  VARCHAR(15) NOT NULL,
   DEPARTMENT CHAR(3) NOT NULL,
   PHONENUMBER CHAR(7),
   AGE  SMALLINT,
   GPA  FLOAT(5)
);

Чтобы выполнить операции извлечения, обновления, удаления или вставки данных SQL-таблицы, необходимо сначала объявить в приложении хост-переменную. Хост-переменная является C/C++-переменной обычного для C/C++ типа: int, float, char и т.д.

Сопроцессор XL C/C++ DB2 хранит данные хост-переменной в наборе данных модуля запросов к базе данных (DBRM) или в файле иерархической файловой системы (HFS).

Объявление хост-переменных

Хост-переменные определяются в блоке DECLARE SECTION (раздел объявлений). Объявление хост-переменной указывает сопроцессору, что она может извлекать данные из SQL-операторов и передавать данные в них. Переменные, не объявленные в этом блоке, не принимаются SQL-операторами.

EXEC SQL BEGIN DECLARE SECTION;
    int student_number;
EXEC SQL END DECLARE SECTION;

Между инструкциями BEGIN и END раздела объявлений могут быть размещены любые допустимые объявления C/C++ для обозначения хост-переменных.

В листинге 2 показан запрос к таблице Students для получения номера студента по имени John Doe. Результат сохраняется в хост-переменной student_number.

Листинг 2. Сохранение SQL-запроса в хост-переменной
EXEC SQL SELECT STUDENTNO
       INTO :student_number
       FROM Students
       WHERE FIRSTNAME = 'John'
       AND LASTNAME = 'Doe';

Примечание. Хост-переменной предшествует символ :. Это единственный способ доступа к хост-переменной в SQL-операторе. Без этого символа имя переменной рассматривается как строковый литерал. Кроме того, для сохранения в хост-переменной результатов оператора SELECT используется оператор INTO.

Подробная информация о хост-переменных

Хост-переменные могут быть спецификаторами стандартного типа, массивами или структурами. На них распространяются те же правила области действия, что и на другие переменные. Хост-переменные можно использовать как любую стандартную переменную XL C/C++, а также в SQL-операторах.

Другими поддерживаемыми типами хост-переменных являются numeric, character, graphic, binary, LOB (Large Object), XML и ROWID. Можно также указать результирующее множество, таблицу, LOB-локаторы и ссылочные переменные LOB или XML-файла. Такие хост-переменные являются более сложными, и их описание выходит за рамки данной статьи.

Примечание. Не все типы данных XL C/C++ имеют SQL-эквиваленты. Например, переменные typedefs, long long и register нельзя объявить как хост-переменные. Дополнительные сведения о других поддерживаемых типах приведены в Руководстве по SQL и программированию приложений.

Практические примеры обращения к SQL-данным

Пример 1. Вставка набора студентов в таблицу

Вспомните таблицу Students в листинге 1. Чтобы заполнить эту таблицу, необходимо вставить в нее набор записей о студентах. Таблица имеет следующую схему:

STUDENTNO → INT  
FIRSTNAME → VARCHAR(12)
LASTNAME  → VARCHAR(15)
DEPTARTMENT → CHAR(3)
PHONENUMBER → CHAR(7)
AGE → SMALLINT
GPA →  FLOAT(5)

Предположим, школьная программа запрашивает сведения о студенте. Раздел объявлений для этой программы выглядит следующим образом:

EXEC SQL BEGIN DECLARE SECTION;
    int student_number;
    char firstname[13];
    char lastname[16];
    char department[4];
    char phonenumber[8];
    short age;
    float gpa;
EXEC SQL END DECLARE SECTION;

Символьные поля требуют особого внимания. SQL-операторы принимают только следующие представления символов:

  • Односимвольная форма.
  • Символьная форма с завершающим нулем.
  • Структурированная форма VARCHAR.
  • CLOB (Character Large Objects – большие символьные объекты).

Например, strcpy(firstname, "John"); – это символьная форма с завершающим нулем.

Листинг 3. Вставка студентов
EXEC SQL INSERT INTO Students
VALUES (:student_number, :firstname, :lastname,
        :department, :phonenumber, :age, :gpa);

Каждая хост-переменная соответствует полю в таблице и заполняет это поле данными.

Пример 2. Выборка записи студента в хост-структуру

Типичным случаем является выборка записи целиком. Вместо объявления хост-переменной для каждого поля приложение может использовать хост-структуру. Хост-структура в принципе аналогична C struct, но инкапсулирует коллекцию хост-переменных.

Для таблицы Students структура определяется следующим образом:

EXEC SQL BEGIN DECLARE SECTION;
struct Student {
    int student_number;
    char firstname[13];
    char lastname[16];
    char department[4];
    char phonenumber[8];
    short age;
    float gpa;
} student_record;
EXEC SQL END DECLARE SECTION;

Теперь можно ссылаться на хост-структуру student_record в операторе SELECT:

EXEC SQL
  SELECT STUDENTNO, FIRSTNAME, LASTNAME, DEPARTMENT,
         PHONENUMBER, AGE, GPA
    INTO :student_record
    FROM Students
    WHERE STUDENTNO = 001;

Каждый элемент хост-структуры student_record будет заполняться значениями полей строки, связанной с номером студента 001.

Пример 3. Извлечение списка средних баллов (GPA) 100 лучших студентов

Теперь, когда база данных заполнена набором студентов, можно перейти к извлечению списка GPA.

Хост-переменные можно объявлять как массивы, используя приведенные ниже операторы объявления:

EXEC SQL BEGIN DECLARE SECTION;
    float gpa_list[100];
EXEC SQL END DECLARE SECTION;

Использование курсоров для извлечения GPA студентов

Для извлечения нескольких строк в одном запросе в приложение следует использовать курсор.

Курсор указывает на подмножество строк, определенное оператором SELECT. Программа приложения затем может получить любое количество строк из этого подмножества. Предположим, запрос выбирает 1000 значений GPA. Эти 1000 значений GPA сохраняются в таблице промежуточных результатов. Можно извлечь любое количество строк из этой промежуточной таблицы в массив за один раз.

Листинг 4. Использование курсоров для извлечения 100 лучших GPA
EXEC SQL DECLARE STUDENTS_C1 CURSOR WITH ROWSET POSITIONING
  FOR SELECT gpa FROM STUDENTS WHERE 1=1 ORDER BY GPA DESC;
EXEC SQL OPEN STUDENTS_C1;
EXEC SQL FETCH NEXT ROWSET FROM STUDENTS_C1 FOR 100
  ROWS INTO :gpa_list;
EXEC SQL CLOSE STUDENTS_C1;

На первом шаге объявляется курсор с именем STUDENTS_C1 и связывается с запросом:

 SELECT gpa FROM Students WHERE 1=1 ORDER BY GPA DESC;

Результаты запроса сохраняются в таблице результатов. После объявления откройте курсор. Это говорит DB2, что он готов для обработки первой строки результатов из оператора select. Затем мы используем оператор fetch для извлечения данных из таблицы результатов. Он позволяет управлять количеством извлекаемых строк и определять место хранения данных. После этого курсор закрывается.

Следующим оператором fetch можно извлечь из таблицы результаты следующего набора 100 лучших GPA.

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

for (int i = 0; i < 100; i++)
{
     printf("GPA: %f ", gpa_list[i]);
}

Переменные-индикаторы для определения пустых записей

Хотя запрос может запрашивать 100 лучших GPA, сама таблица может содержать меньше 100 GPA. Если таблица Students содержит 10 записей, после 10-й итерации цикл будет выводить непредсказуемые значения.

Чтобы обойти эту проблему, DB2 предоставляет переменные-индикаторы. Переменная-индикатор содержит малое целочисленное значение, которое обозначает некоторую информацию о соответствующей хост-переменной.

Переменные-индикаторы могут содержать следующие значения:

  • 0 или положительное целое число
    Выбранное значение не пусто.
  • -1
    Выбранное значение пусто.
  • -2
    Ошибка преобразования числовой строки или пустое значение из-за предупреждений преобразования строки.
  • -3
    Значение не возвращено.
  • Положительное целое число
    Выбранное значение усечено, но не является пустым.

Например, если переменная-индикатор представляет собой массив и в массив из 100 элементов были извлечены 10 элементов, то первым 10 элементам переменной-индикатора должно быть присвоено значение 0.

Перед использованием переменной-индикатора объявите ее как массив gpa_list. Переменные-индикаторы должны быть объявлены как short.

Листинг 5. Инициализация переменных-индикаторов
EXEC SQL BEGIN DECLARE SECTION;
    float gpa_list[100];
    short gpa_indicator[100];
EXEC SQL END DECLARE SECTION;
for (int i = 0; i<100; i++) {  gpa_indicator[i] = -1; }

Каждому элементу gpa_indicator изначально присваивается значение -1 для указания, что массив хост-переменных изначально полностью пуст (содержит только пустые значения).

Оператор fetch можно модифицировать для включения переменной-индикатора:

EXEC SQL FETCH NEXT ROWSET FROM STUDENTS_C1
  FOR 100 ROWS INTO :gpa_list :gpa_indicator;

Обратите внимание, что в операторе fetch переменная-индикатор gpa_indicator следует за хост-переменной gpa_list. Переменная-индикатор может использоваться только после хост-переменной.

Теперь можно изменить цикл, чтобы с учетом индикатора выводить только успешно извлеченные строки (пропуская пустые переменные):

for (int i = 0; i < 100; i++)
{
    if (gpa_indicator[i] >= 0)
       printf("GPA: %f ", gpa_list[i]);
 }

Переча хост-переменных в качестве параметров

Хост-переменные можно передавать в качестве параметров в пользовательские функции, но они не рассматриваются как хост-переменные в области действия локальной функции. Кроме того, параметры функции нельзя включать в блок DECLARE SECTION.

Чтобы обойти эту проблему, можно объявить локальную хост-переменную и присвоить ей значение параметра (для простых типов).

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

Листинг 6. Передача параметров хост-переменной
int selectGPA(int student_number)
{
EXEC SQL BEGIN DECLARE SECTION;
    // Инициализация новой локальной переменной
    int student_number1 = student_number;  
    float gpa;
EXEC SQL END DECLARE SECTION;

EXEC SQL SELECT GPA
       INTO :gpa
       FROM STUDENTS
       WHERE :student_number1 = 12121;
}

int main()
{
EXEC SQL BEGIN DECLARE SECTION;
    int student_number;
EXEC SQL END DECLARE SECTION;

EXEC SQL SELECT STUDENTNO
       INTO :student_number
       FROM STUDENTS
       WHERE FIRSTNAME = "Bill"
       AND LASTNAME = "Doe";
selectGPA(student_number);
}

Альтернативный путь – объявить глобальную хост-переменную.

Благодарности

Авторы благодарят Зиби Сарбиновски (Zibi Sarbinowski), Цзин Чэнь (Jing Chen) и Коби Винаягамурти (Kobi Vinayagamoorthy) за содействие в написании данной статьи.


Ресурсы для скачивания


Похожие темы


Комментарии

Войдите или зарегистрируйтесь для того чтобы оставлять комментарии или подписаться на них.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Rational
ArticleID=973932
ArticleTitle=Введение в методы доступа к данным во встроенном SQL
publish-date=06102014