РУКОВОДСТВО ПО РЕЛЯЦИОННОЙ СУБД DB2

         

ОБРАБОТКА ПРЕДЛОЖЕНИЙ SELECT


Как указывалось ранее, описанная в общих чертах в разделе 12.2 процедура пригодна для динамической подготовки и исполнения всех предложений SQL (точнее, всех предложений SQL, которые могут правильно обрабатываться с помощью PREPARE), за исключением SELECT. Причина такого отличия SELECT состоит в том, что оно возвращает программе данные, в то время как другие предложения возвращают только информацию обратной связи в область связи SQLCA.

Использующей SELECT программе необходимо кое-что знать о значениях тех данных, выборка которых должна производиться, поскольку в ней должно быть специфицировано множество принимающих эти значения целевых переменных. Необходимо знать но крайней мере сколько будет значений в каждой строке результата, а также каковы типы данных и длины этих значений. Если данное предложение SELECT генерируется динамически, программе обычно невозможно заранее «знать» эту информацию. Поэтому она должна получать эту информацию динамически, используя другое предложение динамического SQL, называемое DESCRIBE (описать). Реализуемая такой программой процедура в общих чертах может быть охарактеризована следующим образом.

1. Она формирует и обрабатывает с помощью PREPARE предложение SELECT без фразы INTO. (Обрабатываемое с помощью PREPARE предложение SELECT не должно включать фразу INTO.)

2. Используя DESCRIBE, она запрашивает систему о результатах, которых можно ожидать при исполнении данного предложения SELECT. Описание этих результатов возвращается в область, называемую областью дескрипторов SQL (SQLDA).

3. Далее, в соответствии с только что полученной с помощью DESCRIBE информацией распределяется память для множества целевых переменных, предназначенных для получения результатов. Адреса этих целевых переменных также помещаются в SQLDA.

4. Наконец, с помощью курсора последовательно по одной запрашиваются строки результата. Для этого используются предложения OPEN, FETCH и CLOSE. Если это требуется, в программе можно также использовать для этих строк предложения UPDATE CURRENT (обновить текущую) и DELETE CURRENT (удалить текущую). Эти предложения однако должны, вероятно, реализовываться с помощью PREPARE и EXECUTE.


Для того чтобы описанные идеи стали несколько более конкретными, приведем простой пример, показывающий, как могла бы выглядеть в общих чертах такая программа. Этот пример написан на языке ПЛ/1. Отметим, что он должен быть написан либо на ПЛ/1, либо на языке Ассемблера, поскольку должна иметься возможность динамического распределения памяти. Поэтому интерактивное приложение, осуществляющее выборку данных, должно быть написано на одном из двух указанных языков. Вместе с тем интерактивное приложение, использующее лишь средства, описанные в разделе 12.2, может быть также написано, если это требуется, на Коболе или Фортране. Перейдем теперь к примеру.

DCL ИСХОДНЫЙ_SQL         CHAR(256) VARYING;

EXEC       SQL     DECLARE ОБЪЕКТНЫЙ_SQL STATEMENT;

EXEC       SQL     DECLARE X CURSOR FOR ОБЪЕКТНЫЙ_SQL;

EXEC       SQL     INCLUDE        SQLDA;

/* Пусть максимальное число ожидаемых значений, подлежащих выборке, равно N */



SQLSIZE = N;

ALLOCATE SQLDA;

ИСХОДНЫЙ_SQL = 'SELECT * FROM SP WHERE

КОЛИЧЕСТВО > 100';

EXEC       SQL     PREPARE ОБЪЕКТНЫЙ_SQL FROM  :ИСХОДНЫЙ_SQL;

EXEC       SQL     DESCRIBE ОБЪЕКТНЫЙ_SQL INTO SQLDA;

/* Теперь наряду с прочей информацией SQLDA содержит следующее:             */

/* — в SQLN — фактическое число подлежащих выборке значений                          */

/* — в SQLVAR(i) — тип данных и длину i-го значения.                                 */

/* Используя возвращаемую DESCRIBE информацию, программа может     */

/* теперь распределить память для каждого значения, выборка                     */

/* которого должна быть осуществлена, и поместить адрес i-й                                  */

/* выделенной области в

SQLVAR(i). Тогда:                                                    */

EXEC       SQL     OPEN X;

DO       WHILE (еще — поступают— записи);

EXEC SQL     FETCH X

USING             DESCRIPTOR             SQLDA;

 .  .  .  . 

END;

EXEC       SQL     CLOSE X;

Пояснение. Здесь ИСХОДНЫИ_SQL и ОБЪЕКТНЫЙ_SQL имеют в основном такой же смысл, как и ранее: ИСХОДНЫЙ_SQL будет содержать предложение SQL в исходном формате (в данном примере, конечно, предложение SELECT), а ОБЪЕКТНЫЙ_SQL — это же предложение в соответствующем объектном формате. X — курсор для этого SELECT. Обратите внимание, что он описывается предложением DECLARE CURSOR нового формата:



EXEC       SQL     DECLARE       имя — курсора CURSOR FOR имя — предложения;

Объявление области дескрипторов SQL включается в программу с помощью предложения:

EXEC       SQL     INCLUDE        SQLDA;

Это предложение генерирует объявление структуры SQLDA в языке ПЛ/1, а также объявление числовой переменной SQLSIZE. Программа должна установить SQLSIZE, равное N, где N — верхняя граница числа значений, которые должны быть выбраны в каждой строке предложением SELECT, выделить память для SQLDA. Объем выделяемой памяти будет функцией значения SQLSIZE.

Далее, в строке ИСХОДНЫЙ_SQL формируется требуемое предложение SELECT в исходном формате, которое затем обрабатывается с помощью PREPARE. В результате будет получен в ОБЪЕКТНЫИ_SQL соответствующий его объектный формат. После этого программа выдает команду DESCRIBE в связи с переменной ОБЪЕКТНЫИ_SQL с тем, чтобы получить описание значений, ожидаемых в каждой строке результата исполнения этого предложения SELECT. Такое описание состоит из двух частей:

а) фактическое число значений, подлежащих выборке, указывается в поле SQLN структуры SQLDA;

б) тип данных и длина каждого такого значения указываются в массиве SQLVAR структуры SQLDA.

Используя это описание, программа может теперь распределить помять для каждого из этих значений. Далее она помещает адреса выделенных областей памяти в SQLDA, а точнее — в массив SQLVAR.

Наконец, для выборки фактических данных программа использует предложения OPEN, FETCH и CLOSE в связи с курсором X. Следует обратить внимание, что при этом используется новый формат предложения FETCH. Вместо фразы INTO оно включает фразу USING DESCRIPTOR, а структура, указанная в этой фразе (обычно SQLDA), в свою очередь идентифицирует целевые переменные для подлежащих выборке значений.

С помощью PREPARE можно также обрабатывать предложения SELECT, которые содержат параметры, указываемые вопросительным знаком. Например:

ИСХОДНЫЙ_SQL =       'SELECT          *

FROM              SP

WHERE           КОЛИЧЕСТВО > ?

AND                КОЛИЧЕСТВО < ?';

ЕXEC SQL PREPARE ОБЪЕКТНЫЙ_SQL FROM  :ИСХОДНЫЙ_SQL;

Аргументы специфицируются в соответствующем предложении OPEN. Например:

ЕXEC SQL OPEN X USING НИЖНЕЕ_ЗНАЧЕНИЕ, :ВЕРХНЕЕ_ЗНАЧЕНИЕ;

К SELECT не применяется предложение EXECUTE. Если выполняемое предложение—SELECT, функция EXECUTE выполняется предложением OPEN.


Содержание раздела