Вернемся теперь к случаю предложения SELECT, которое продуцирует целое множество записей, а не только одну запись. Как уже было объяснено в разделе 10.2, здесь необходим механизм, обеспечивающий последовательный доступ к записям в этом множестве. Такой механизм обеспечивают курсоры. В общих чертах процесс доступа иллюстрируется в примере, приведенном на рис. 10.2, в котором предусматривается выборка деталей (полей НОМЕР_ДЕТАЛИ, НАЗВАНИЕ и СОСТОЯНИЕ) для всех поставщиков, находящихся в городе, заданном переменной включающего языка Y.
ЕХЕС SQL DECLARE X CURSOR FOR / * определить курсор X * /
SELECT НОМЕР_ПОСТАВЩИКА, НАЗВАНИЕ,
СОСТОЯНИЕ
FROM S
WHERE ГОРОД = > У;
ЕХЕС SQL OPEN X; / * исполнить запрос * /
DO WHILE (пока еще есть записи);
ЕХЕС SQL FETCH X INTO:НОМЕР_
ПОСТАВЩИКА,:НАЗВАНИЕ,:СОСТОЯНИЕ;
/ * выбрать следующего поставщика * /
END;
ЕХЕС SQL CLOSE X; / * дезактивировать курсор Х * /
Рис. 10.2. Выборка множества записей
Пояснение. Предложение DECLARE X CURSOR... определяет курсор, названный X, и ассоциированный с ним запрос, специфицированный с помощью предложения SELECT, которое образует часть этого предложения DECLARE. Указанное предложение SELECT не исполняется в данный момент, так как DECLARE CURSOR это чисто декларативное предложение. Оно исполняется, когда открывается курсор в процедурной части программы. Предложение FETCH... INTO... (выбрать... в...) используется для выборки записей результирующего множества и присваивает найденные значения переменным включающего языка в соответствии со спецификациями фразы INTO в этом предложении. Для простоты в приведенном примере переменным включающего языка даны те же самые имена, что и соответствующим полям базы данных. Заметим, что предложение SELECT в объявлении курсора не содержит фразы INTO. Поскольку в результате будет получено множество записей, предложение FETCH будет обычно входить в некоторый цикл (в языке ПЛ/1—DO... END). Этот цикл будет повторяться до тех пор, пока в этом результирующем множестве еще существуют непросмотренные записи. При выходе из цикла курсор Х закрывается (дезактивируется) с помощью соответствующего предложения CLOSE(закрыть).
|
|
Давайте теперь рассмотрим курсоры и операции над курсорами более подробно. Прежде всего нужно отметить, что курсор объявляется с помощью предложения DECLARE CURSOR (объявить курсор), которое имеет следующий общий формат:
ЕХЕС SQL DECLARE имя — курсора CURSOR
FOR подзапрос [UNION подзапрос]...
[FOR UPDATE OF имя — столбца [,имя — столбца]...
[фраза — упорядочить — по];
Для примера обратимся к рис. 10.2. Как указывалось ранее, предложение DECLARE CURSOR является декларативным, а не исполняемым. Оно объявляет курсор с заданным именем, с которым постоянно связан специфицированный подзапрос или множество подзапросов, соединенных операций UNION. Заметим, что эти подзапросы могут включать ссылки на переменные включающего языка. Если курсор будет использоваться в предложениях UPDATE CURRENT (обновить текущую) (См. ниже в этом разделе.— Примеч пер), то его объявление должно включать фразу FOR UPDATE(для обновления), специфицирующую все поля, которые будут обновляться через этот курсор. Если курсор не используется для обновления с помощью указанного предложения, то его объявление факультативно может включать фразу ORDER BY(упорядочить по), как в обычном предложении SELECT. Эта фраза будет управлять порядком, в котором строки результата выбираются с помощью предложения FETCH. Заметим поэтому, что невозможно осуществлять выборку множества записей через курсор в некотором специфицированном порядке и в то же время обновлять (операция UPDATE) некоторые из этих записей через тот же самый курсор.
|
|
Программа может включать произвольное число предложений DECLARE CURSOR, которые, конечно, объявляют различные курсоры.
Для выполнения операций над курсорами специально обеспечиваются три исполняемых предложения: OPEN, FETCH и CLOSE.
1. Предложение
ЕХЕС SQL OPEN имя — курсора;
открывает или активизирует специфицированный курсор, который в этот момент не должен быть открыт. Фактически исполняется предложение SELECT, связанное с этим курсором. При этом используются текущие значения для всех переменных включающего языка, на которые имеются ссылки в этом предложении SELECT. Таким образом, идентифицируется некоторое множество записей, которое становится активным множеством для данного курсора. Курсор идентифицирует также позицию в этом множестве, а именно позицию непосредственно перед первой записью данного множества. Активные множества всегда рассматриваются как упорядоченные, так что концепция позиции имеет смысл. При этом имеется в виду упорядочение, определяемое фразой ORDER BY, либо системой в отсутствие этой фразы.
2.Предложение
ЕХЕС SQL FETCHимя — курсора INTO мишень [, мишень]...;
где каждая «мишень» имеет формат
переменная — включающего — языка [:переменная — включающего — языка]
как в единичном SELECT, и где идентифицированный курсор должен быть открыт, продвигает этот курсор к следующей записи в активном множестве, а затем присваивает значения полей из этой записи переменным включающего языка, в соответствии с фразой INTO. Как уже указывалось, предложение FETCH обычно исполняется в программном цикле (см. рис. 102). Если при исполнении FETCH не существует следующей записи, то выборка данных не производится и SQLCODE принимает значение +100.
Отметим, между прочим, что «выбрать следующую» представляет собой единственную операцию перемещения курсора. Невозможно переместить курсор, например, «вперед на три позиции» или «назад на две позиции» и т. п.
3. Предложение
ЕХЕС SQL CLOSE имя — курсора;
закрывает или дезактивирует специфицированный курсор, который в этот момент должен быть открыт. Теперь этот курсор не имеет соответствующего активного множества. Его можно, однако, теперь снова открыть. В этом случае с ним будет связано другое активное множество, вероятно, не в точности то же самое, что и ранее, особенно если значения переменных включающего языка, упоминаемые в предложении SELECT, тем временем изменились. Заметим, что изменение значений этих переменных в то время, когда курсор открыт, не оказывает влияния на активное множество.
Два следующих предложения могут включать ссылки на курсоры. Имеются формы CURRENT для предложений UPDATEи DELETE. Если, например, курсор Х в настоящее время позиционирован на конкретную запись в базе данных, то можно обновить (UPDATE) или удалить (DELETE) «текущую X», т. е. запись, на которую позиционирован X. Синтаксис этих предложений таков:
|
|
ЕХЕС SQL UPDATE имя — таблицы
SET имя — поля = выражение
[, имя — поля == выражение]...
WHERE CURRENT OF имя — курсора;
ЕХЕС SQL DELETE
FROMимя — таблицы
WHERE CURRENT OF имя — курсора;
Пример:
ЕХЕС SQL UPDATE S
SET СОСТОЯНИЕ = СОСТОЯНИЕ +:ПРИРОСТ
WHERE CURRENT OF X;
Использование предложений UPDATE CURRENT и DELETE CURRENT не допускается, если предложение SELECT в объявлении курсора включает UNION или ORDER BY, или если это предложение SELECT определяет необновляемое представление и является частью предложения CREATE VIEW (см. раздел 8.4). Как пояснялось ранее, в случае UPDATE CURRENT предложение DECLARE должно включать фразу FOR UPDATE, идентифицирующую все поля, которые входят как мишени во фразу SET предложения UPDATE CURRENT для этого курсора.