Цикл FOR
Возможно, циклы FOR - самая важная разновидность циклов, реализованных в PL/pgSQL. Цикл FOR выполняет программный блок для целых чисел из заданного интервала. У циклов FOR в PL/pgSQL существуют аналоги в других процедурных языках программирования.
Заголовок цикла FOR начинается с объявления целочисленной переменной, управляющей выполнением цикла. Затем указывается интервал принимаемых ею значений, а далее следует блок команд. Управляющая переменная уничтожается сразу же после выхода из цикла, причем ее не нужно объявлять в секции объявлений блока.
Синтаксис цикла FOR:
[ «метка» ]
FOR переменная IN [ REVERSE ] выражение! . . выражение? LOOP
команда;
[...]
END LOOP;
Цикл FOR выполняет одну итерацию для каждого значения переменной переменная в интервале, границы которого определяются выражениями выражение! и выражение? (включительно). В начале цикла переменная инициализируется значением выражения выражение! и увеличивается на 1 после каждой итерации. Если в заголовке цикла присутствует ключевое слово REVERSE, то переменная не увеличивается, а уменьшается.
ПРИМЕЧАНИЕ Управляющую переменную цикла не обязательно объявлять вне блока FOR, если вы не собираетесь работать с ней после завершения цикла.
Циклы FOR также используются для перебора результатов запросов. Пример приведен в листинге 6.38, где цикл FOR работает с переменными RECORD и %ROWTYPE.
Синтаксис цикла FOR с перебором записей:
[ «метка» ]
FOR { переменная_record %переменная_rowtуре } IN секция_select LOOP
команда;
[...]
END LOOP;
В листинге 6.38 функция extract_all_titles() получает из базы данных список всех названий книг, упорядоченных по теме. Если по какой-либо теме в базе данных не находится ни одной книги, выводится пустая строка. Список возвращается в виде текстовой переменной. Перебор тем по кодам в функции extract_all_titles() осуществляется в цикле FOR.
Внутри первого цикла FOR находится другой, вложенный цикл FOR. Он перебирает все книги в базе данных и отбирает те из них, у которых поле subject_id совпадает с управляющей переменной исходного цикла (текущим кодом темы). В листинге 6.38 управляющая переменная i инициализируется нулевым значением, поскольку нумерация кодов тем в таблице subjects начинается с 0.
Листинг 6.38. Пример использования цикла FOR
CREATE OR REPLACE FUNCTION books.extract_all_titles()
RETURNS text AS
$BODY$
DECLARE
-- Объявление переменной для кода темы.
sub_id integer;
-- Объявление переменной для хранения списка названий книг.
text_output text := ' ';
-- Объявление переменной для названия темы.
sub_title text;
-- Объявление переменной для хранения записей,
-- полученных при выборке из таблицы books.
row_data books.books%ROWTYPE;
BEGIN
-- Внешний цикл FOR: тело цикла выполняется до тех пор,
-- пока переменная 1 не станет равна 15. Перебор начинается с 0.
-- Следовательно, тело цикла будет выполнено 16 раз
-- (по одному пля каждой темы).
FOR i IN 0..15 LOOP
-- Получить из таблицы subjects название темы,
-- код которой совпадает со значением переменной i.
SELECT INTO sub_title subject FROM books.subjects WHERE id = i;
-- Присоединить название темы, двоеточие и символ новой строки
-- к переменной text_output.
text_output := text_output || ' ' || sub_title || ': ';
-- Перебрать все записи таблицы books,
-- у которых код темы совпадает со значением переменной i.
FOR row_data IN SELECT * FROM books.books WHERE subject_id = i
LOOP
-- Присоединить к переменной text_output название книги
-- и символ новой строки.
text_output := text_output || row_data.title || '; ';
END LOOP;
END LOOP;
-- Вернуть список.
RETURN text_output;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE
В листинге 6.39 приведена другая функция, в которой цикл FOR используется для перебора результатов запроса SQL. При каждой итерации цикла FOR в листинге 6.39 содержимое одной из записей запроса к таблице books помещается в переменную row_data, после чего значение поля title присваивается переменной text_output.
Цикл продолжается до тех пор, пока не будет достигнута последняя запись в таблице books. В конце цикла переменная text_output содержит полный список всех книг по теме, код которой был передан в аргументе функции. Работа функции завершается возвращением переменной text_output.
Листинг 6.39. Использование цикла FOR с атрибутом %ROWTYPE
CREATE OR REPLACE FUNCTION books.extract_title(integer)
RETURNS text AS
$BODY$
DECLARE
-- Объявление псевдонима для аргумента функции.
sub_id ALIAS FOR $1;
-- Объявление переменной для хранения названий книг.
-- Переменная инициализируется символом новой строки,
text_output text := ' ';
-- Обьявление переменной для хранения записей
-- таблицы books.
row_data books.books%ROWTYPE;
BEGIN
-- Перебор результатов запроса.
FOR row_data IN SELECT *
FROM books.books
WHERE subject_id = sub_id
ORDER BY title
LOOP
-- Присоединить название книги к переменной text_output.
text_output := text_output || row_data.title || '; ';
END LOOP;
-- Вернуть список книг.
RETURN text_output;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE
В листинге 6.40 показан результат вызова функции extract_title() с аргументом 2. В таблице subjects этот код соответствует теме «Children's Books» (книги для детей).
Листинг 6.40. Результат выполнения функции extract_title(2)
SELECT books.extract_title(2);
Bartholomew and the Oobleck;
Franklin in the Dark;
Goodnight Moon;
The Cat in the Hat;
Переменная row_data объявляется с атрибутом %ROWTYPE no отношению к таблице books, поскольку она будет использоваться только для хранения записей из таблицы books. С таким же успехом можно было объявить row_data с типом RECORD:
row_data RECORD;
Но это следует делать только в том случае, если в переменной предполагается хранить записи из нескольких таблиц.
Функция extract_title() возвращает одинаковые результаты как при объявлении переменной с типом RECORD, так и с атрибутом %ROWTYPE.
Дата добавления: 2015-02-03; просмотров: 771;