Хранимые процедуры выбора называются так, потому что они разрабатываются для выполнения с помощью оператора SELECT. для читателей, привыкших к техникам программирования на сервере, доступным в других СУБД, концепция хранимой процедуры, которая передает строки непосредственно вызвавшему приложению или процедуре без создания промежуточной "временной" таблицы, будет менее понятной, чем выполняемые процедуры.
Процедуры выбора могут быть использованы для виртуального задания любого набора, однако они особенно полезны, когда нужен набор, который не может быть извлечен или его извлечение выполняется медленно или слишком сложно в одном операторе DSQL.
Техника хранимых процедур выбора предоставляет колоссальную гибкость для извлечения наборов; эта техника превосходит логику, доступную в спецификациях
обычных операторов SELECT. Она делает возможным создавать набор буквально из любой комбинации хранимых у вас данных. Вы можете выполнять вычисления и трансформацию множества столбцов и строк в выходной набор. Например, выходные наборы с промежуточными суммами сложно или невозможно получить из динамического набора, но они могут быть быстро и эффективно сгенерированы с помощью хранимых процедур выбора.
Процедуры выбора могут легко генерировать наборы из данных, которые вообще не хранятся в базе данных. Мы все иногда находим применение этой технике. В следующем тривиальном примере список строк, разделенных запятыми, каждая из которых содержит 20 или менее символов, поступает в качестве входа. Процедура возвращает приложению каждую строку в нумерованном виде:
CREATE PROCEDURE BREAKAPART(
INPUTLIST VARCHAR(1024))
RETURNS (
NUMERO SMALLINT, ITEM VARCHAR (20)
)
AS
DECLARE CHARAC CHAR;
DECLARE ISDONE SMALLINT = 0;
BEGIN
NUMERO = 0;
ITEM = ' ' ;
WHILE (ISDONE = 0) DO
BEGIN
CHARAC = SUBSTRING (INPUTLI ST FROM 1 FOR 1);
IF (CHARAC = '') THEN
ISDONE = 1;
IF (CHARAC = OR CHARAC = '') THEN
BEGIN
NUMERO = NUMERO + 1;
SUSPEND;
/* Отправляет строку в буфер строк */
ITEM = '';
END
ELSE
ITEM = ITEM || CHARAC;
INPUTLIST = SUBSTRING(INPUTLIST FROM 2);
END
END ^
COMMIT;
/* */
SELECT * FROM BREAKAPART (' ALPHA, BETA, GAMMA, DELTA ') ;
NUMERO ITEM
1 ALPHA
2 BETA
3 GAMMA
4 DELTA
Часто сложные запросы, включающие множество соединений или подзапросов, бывают слишком медленными, чтобы удовлетворить интерактивные приложения. Некоторые запросы могут быть медленными по причине непропорциональности индексов внешних ключей. Поскольку есть возможность оперировать с наборами во внутренних циклах, хранимые процедуры способны создавать требуемые наборы гораздо быстрее и к тому же начинаются возвращать строки раньше, чем позволяют обычные последовательности SQL.
Техника извлечения и манипулирования данными выходного набора использует курсор для чтения по порядку каждой строки из оператора SELECT В предварительно объявленный набор переменных. Часто это могут быть выходные аргументы, куда помещаются значения столбцов, однако это могут быть и локальные переменные. Внутри цикла с переменными выполняются действия соответствующим образом: преобразовываются для вычислений, если необходимо, или используются как аргументы поиска для вложенных циклов, чтобы получать данные из других запросов. В конце цикла, когда все выходные аргументы получают конечные значения, оператор SUSPEND приводит к паузе в выполнении, пока этот набор передается в кэш строк. Выполнение возобновляется, когда вызывается следующая пересылка.
Как мы видели в предыдущем примере BREAKAPART, оператор SUSPEND является тем элементом, который заставляет процедуру передавать строку.
Для поиска множества строк в процедуре мы используем конструкцию FOR SELECT ... DO. Ее синтаксис:
FOR
<выражение-выбора>
INTO <:переменная [, :переменная [, ...]] DO
<составной-оператор>;
<выражение-выбора> может быть любым запросом выбора, использующим соединения, объединения, просмотры, другие процедуры выбора, вызовы функций и т.д. в любой допустимой комбинации.
Оператор FOR SELECT отличается от стандартного оператора SELECT тем, что требует наличия переменных, в которые помещаются значения столбцов, и спецификации полей.
<составной-оператор> может быть одним оператором SUSPEND или блоком из двух или более операторов. <составной-оператор> может иметь вложенные составные операторы.
FOR SELECT ... DO является конструкцией цикла, которая отыскивает строку, заданную в <выражении-выбора>, и выполняет для каждой строки оператор или блок операторов, следующих после DO.
Предложение INTO <переменные> обязательно и должно быть последним[116].
На рис. 30.2 проиллюстрированы типичные виды деятельности, которые могут выполняться внутри циклов для генерации выхода в хранимой процедуре выбора.
Рис. 30.2. Операции в процедуре выбора
В следующих примерах мы посмотрим на то, как комбинации операций в PSQL могут представить более интересную область SQL.