Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Работа с Oracle / Язык PL SQL.docx
Скачиваний:
15
Добавлен:
28.06.2021
Размер:
768.74 Кб
Скачать

Работа с курсорами

Каждый раз, когда приложение передает SQL-команду СУБД Oracle, сервер открывает для обработки этой команды, по крайней мере, один курсор (рабочую область для команды SQL). Когда программа PL/SQL (или любое другое приложение) представляет команду INSERT, UPDATE или DELETE, Oracle автоматически открывает курсор для ее обработки. Oracle может автоматически обрабатывать команду SELECT, которая возвращает только одну строку.

Для обработки запроса, возвращающего результирующую таблицу из нескольких строк, программа PL/SQL должна явным образом объявить курсор, открыть его, извлекать из него строки по одной, а затем закрыть курсор. Oracle может применять к обработке курсора различные подходы.

  1. Объявление именованного курсора (команды OPEN, FETCH, CLOSE)

Пользователь может явным образом объявить курсор с именем в разделе объявлений блока используя команду CURSOR. После этого можно открыть курсор в теле блока или в разделе обработки исключений с помощью команды OPEN, извлекать из него строки с помощью команды FETCH (обычно в цикле) и в заключение закрыть курсор командой CLOSE. Это наиболее трудоемкий подход, он чреват ошибками и является наихудшим в отношении производи­тельности.

  1. Явно задаваемый цикл FOR для курсора

Пользователь может объявить курсор командой CURSOR, а затем использовать цикл FOR для курсора для автоматического объявления переменной или записи, которая используется для получения строк из курсора. После открытия курсора из него извлекаются строки, и после извлечения последней курсор закрывается. Такой подход проще, менее подвержен ошибкам, обеспечивает более высокую производительность, но все же требует явного объявления курсора.

  1. Неявный цикл FOR для курсора

Кроме объявления переменной или записи для приема строк из курсора пользователь может объявить курсор в самом цикле FOR и обрабатывать соответст­вующие строки по одной. Такой подход намного проще и обеспечивает такую же производительность, как и использование явного цикла FOR для курсора.

При использовании курсора для обработки большого количества строк циклы FOR курсора обеспечивают значительно большую производительность, чем использование команд OPEN/FETCH/CLOSE. Циклы FOR курсора извлекают за один раз из соответствующего курсора массив в 100 строк, тогда как при использовании для обработки курсора команд OPEN/FETCH/CLOSE Oracle извлекает за один раз лишь одну строку.

Рассмотрим анонимный блок, в котором объявляется и используется очень простой курсор для распечатки избранных полей из всех строк таблицы Users.

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

Вэтой версии блока после извлечения из курсора первой записи последующие строки извлекаются из открытого курсора по одной с помощью цикла WHILE. В условии цикла WHILE используется атрибут курсора %FOUND для определения момента, когда из курсора извлекается последняя строка.

Атрибуты явным образом объявленных курсоров, которые можно использовать в языке PL/SQL для базовых курсоров.

  • cursor%FOUND – атрибут %FOUND получает значение TRUE, если предшествующей команде FETCH соответствует по крайней мере одна строка в базе данных; иначе атрибут полу­чает значение FALSE;

  • cursor%NOTFOUND – атрибут %NOTFOUND получает значение TRUE, если предшествующей команде FETCH не соответствует ни одной строки в базе данных; иначе атрибут %NOTFOUND получа­ет значение FALSE;

  • cursor%ISOPEN – атрибут %ISOPEN получает значение TRUE если курсор-источник открыт; иначе атрибут %ISOPEN получает значение FALSE.

  • cursor%ROWCOUNT – атрибут %ROWCOUNT указывает количество строк, извлеченных до настоящего момента из явным образом объявленного курсора.

Приведем еще одну версию предыдущего блока, в которой для курсора используется явный цикл FOR:

Операции с текущей строкой курсора. Так как программа извлекает строки из результирующей таблицы по одной, она в каждый момент имеет доступ к текущей строке курсора. Когда нужно обновить или удалить текущую строку курсора, метод, используемый для обращения к этой строке, зависит от подхода, применяемого для обработки курсора. При использовании неявного цикла FOR курсор должен выбирать адрес ROWID каждой строки и в условии блока WHERE использовать ROWID строки-источника:

ROWID представляет собой физический адрес, который указывает Oracle, где физически находится соответствующая строка базы данных. Как показано выше, на ROWID можно ссылаться с использованием псевдо­столбца ROWID.

Предыдущий блок удаляет две новых записи, вставленные в таблицу Catalogs программами предыдущих примеров. При объявлении курсора для обновления или удале­ния строк, извлеченных курсором, необходимо объявить определяю­щий запрос курсора с ключевыми словами FOR UPDATE. Это требование заставляет Oracle блокировать строки в результирующей таблице курсо­ра, что предотвращает изменение или удаление этих строк другими транзакциями, до тех пор, пока для транзакции не будет выполнена фик­сация или откат.

Программа PL/SQL, которая явным образом объявляет курсор, мо­жет воспользоваться специальным блоком CURRENT OF в условии блока WHERE директив UPDATE или DELETE для обработки текущей строки курсора. Следующий анонимный блок эквивалентен предыдущему блоку:

Эта про­грамма также показывает, что при объявлении курсора пользователь мо­жет также объявить один или более параметров курсора (p_catID), которые программа PL/SQL будет использовать для определения критерия выбора записи в курсоре во время выполнения программы.

Работа с коллекциями

В блоках PL/SQL могут объявляться и использоваться коллекции. Коллекция представляет собой переменную – упоря­доченный набор аналогичных элементов. Для создания коллекции необ­ходимо сначала объявить либо тип вложенной таблицы, либо тип пере­менного массива varray (varying array), а затем объявить переменную типа коллекция.

Вложенные таблицы

Программа PL/SQL может использовать тип вложенных таблиц для созда­ния переменных, имеющих один или более столбцов и неограниченное ко­личество строк, подобно таблицам в базе данных.

Следующий анонимный блок демонст­рирует объявление типа вложенной таблицы, а затем использование это­го типа для объявления новой переменой типа коллекция. Пример также иллюстрирует инициализацию коллекции принадлежащим ей ме­тодом конструктора с последующим обращением к отдельным элементам этой вложенной таблицы по индексу (subscript).

Этот пример демонстрирует принципиальные аспекты использования вложенных таблиц:

  • Перед использованием коллекции (такой как вложенные таблицы) ее необходимо инициализировать, используя конструктор данного типа. PL/SQL автоматически предоставляет пользователю конструктор с тем же именем, которое имеет коллек­ция. При вызове конструктора для инициализации переменной коллекции можно указать список разделенных запятыми первона­чальных элементов коллекции или пустые скобки для ини­циализации значениями Null.

  • Коллекция вложенных таблиц может иметь любое количество строк. При необходимости размер таблицы увеличивается или уменьшается динамически в процессе работы программы.

PL/SQL поддерживает несколько методов, которые можно ис­пользовать при работе с коллекциями. Для использования метода в программе указывается имя коллекции и после имени название метода с использованием точечной нотации. В таблице приведены методы коллекций, поддер­живаемые в языке PL/SQL.

Метод коллекции

Описание

COUNT

DELETE[(x[,y]...)]

EXISTS(x)

EXTEND[(x[,y])]

FIRST

LAST

LIMIT

NEXT(x)

PRIOR(x)

TRIM(x)

Возвращает текущее количество элементов в коллекции

Удаляет некоторые или все элементы коллекции, не выделяя ос­вободившееся место другим объектам

Возвращает логическое значение TRUE, если существует элемент коллекции с номером х. Иначе метод возвращает значение FALSE

Добавляет х копий элемента с номером ув окончание коллекции. Если параметр у опущен, то добавляет к коллекции х элементов со значением null. Если оба параметра х и у опущены, то к коллекции добавляется один элемент со значением null

Возвращает индекс первого элемента коллекции

Возвращает индекс последнего элемента коллекции

Возвращает максимальное количество элементов, которое может содержать коллекция массива varray

Возвращает индекс элемента, находящегося в коллекции непосредственно за элементом х

Возвращает индекс элемента, коллекции непосредственно пред­шествующего элементу х

Удаляет х элементов коллекции, считая от ее конца

Приведенный ниже анонимный блок иллю­стрирует применение методов коллекции EXTEND, COUNT, FIRST, NEXT и DELETE к вложенной табли­це с записями.

Вложенные таблицы являются первоначально плотными (индексы элементов последовательно увеличиваются на единицу), но позднее могут становиться разреженными (в последовательной индексации могут появиться разрывы), если программа удаляет элемен­ты из коллекции. Поэтому циклы, выводящие элемен­ты, не используют переменную счетчика для обраще­ния к элементам коллекции.

Массивы переменной длины

Программа может использовать тип varray (varying array – массив переменной длины) для создания подобных таблицам переменных, кото­рые имеют один или несколько столбцов и ограниченное количество строк.

В основном varray-коллекции подобны коллекциям вложенных таб­лиц, но имеют следующие важные отличия:

  • при объявлении переменной типа varray необходимо задать коли­чество элементов в переменном массиве, которое остается посто­янным;

  • массивы переменной длины должны оставаться плотными;про­грамма не может удалять элементы из таких массивов.

Обработка программных исключений

В PL/SQL обработка ошибок осуществляется с помощью исключений и связанных с ними обработчиков. Исключение представляет собой именованное условие возникновения ошибки. Про­грамма генерирует исключение с именем при обнаружении ошиб­ки, а затем передает управление подпрограмме обработки исключений, которая отделена от тела основной программы.

PL/SQL включает в себя много предопределенных исключений, соответствующих типичным ошибкам в Oracle. Когда программа сталкивается с предопределенным исключением, она автоматически пе­редает управление соответствующему обработчику исклю­чений – программа не должна явно выполнять проверку предопределен­ных исключений.

PL/SQL идентифицирует несколько предопределенных исключений:

  • программа автоматически генерирует исключение NO_ DATA_FOUND, если результирующая таблица команды SELECT INTO не содержит ни одной строки;

  • программа автоматически генерирует исключение ТОО_ MANY_ROWS, если результирующая таблица команды SELECT INTO содержит более одной строки.

Полный список предопределенных исключений представлен в Ру­ководстве и Справочнике пользователя по Oracle PL/SQL.

Следующий анонимный блок включает в себя обработчики для предопределенных исключений NO_DATA_FOUND и TOO_MANY_ROWS:

Пример демонстрирует несколько важных моментов обработ­ки исключений:

  • Раздел обработки исключений можно включать в любой блок – как анонимный блок, так и его подпрограмма (про­цедура printOrder) имеют свои собственные разделы обработки ис­ключений.

  • Первый вызов процедуры printOrder не генерирует никаких ис­ключений и печатает код единственного заказа, разме­щенного клиентом с кодом 1.

  • Второй вызов процедуры printOrder генерирует предопределен­ное исключение NO_DATA_FOUND, поскольку оператор SELECT ... INTO в процедуре не извлекает строк. Локаль­ный по отношению к процедуре обработчик исключения обрабатывает исключение путем распечатки сооб­щения, а затем возвращает управление вызывающей программе (анонимному блоку). Этот блок затем вызывает проце­дуру printOrder в третий раз.

  • Третий вызов процедуры printOrder генерирует предопределен­ное исключение TOO_MANY_ROWS, поскольку оператор SELECT ... INTO в процедуре возвращает более одной строки. Раздел обработки исключений процедуры не обрабаты­вает исключение TOO_MANY_ROWS локально, поэтому исключе­ние передается вызывающей программе (анонимному блоку), у которой есть обработчик исключения ТОО_ MANY_ROWS. Обработчик печатает сообщение, а затем передает управление вызывающей программе (страница SQL-команд Oracle SQL Developer). Выполне­ние анонимного блока останавливается, и четвертое об­ращение к процедуре printOrder никогда не произойдет.

Если необрабатываемое исключение генерируется или передается внешнему блоку, то этот блок останавливает выполнение и возвращает в вызываю­щую программу номер ошибки и сообщение, которое соответствует исключению.

В разделе объявлений блока можно также объявлять пользовательские ис­ключения. Однако чтобы сгенерировать исключе­ние, программа должна явно выполнять проверку пользовательского исключения.

Следующий анонимный блок де­монстрирует использование пользовательских исключений.

Данный пример иллюстрирует несколько интересных аспектов обра­ботки пользовательских исключений:

  • пользовательское исключение объявляется в секции объявлений PL/SQL-блока с помощью ключевого слова EXCEPTION;

  • пользовательское исключение генерируется с помощью PL/SQL-команды RAISE;

  • программа может использовать обработчик WHEN OTHERS для обработки всех исключений, не имеющих специальных обработчиков;

  • в программе можно использовать специальные функции SQLCODE и SQLERRM, которые возвращают соответственно номер и текст сообщения последней ошибки Oracle.

Типы программ PL/SQL

Рассмотрим различные типы программ, которые можно создавать с помощью языка PL/SQL (анонимные блоки, процедуры, функции, пакеты и триггеры).

Анонимные блоки языка PL/SQL

Все предыдущие примеры представляют собой анонимные блоки PL/SQL, Анонимным блоком называется блок, нахо­дящийся внутри создаваемого приложения. Такой блок не имеет имени и не хранится в базе данных. Приложение отправляет этот блок кода серверу баз данных для обработки в режиме исполнения.

Хранимые процедуры и функции

Выше было показано, как объ­являть и использовать подпрограммы PL/SQL (процедуры и функции) внутри блоков. Проце­дуры и функции можно хранить как скомпилированные блоки ло­гики приложения внутри базы данных Oracle в виде именованных объек­тов схемы.

Преимущества хранения подпрограмм в базе данных:

  • Возможность повторного использования кода и повышение продуктивности разработчиков. Концентрация общих процедур и функций в базе данных позволяет использовать эти подпрограммы в любом приложении. Рациональное использование хранимых процедур и функций может повысить продуктивность разработчика и упростить создание приложения.

  • Целостность данных. Как только правильность хранимых подпрограмм подтверждена, приложения могут полагаться на них как на методы доступа к данным, не нарушающие целостность данных в базе.

  • Безопасность. Хранимые подпрограммы представляют собой скомпилированные программы для доступа к информации, которые скрывают доступные для них основные структуры базы данных. Только владелец подпрограммы, а не все вызывающие ее пользователи, имеет привилегии для доступа к основным структурам данных.

Для создания хранимой процедуры в базе данных Oracle используется SQL-команда CREATE PROCEDURE. Хранимые процедуры объявляются так же, как и процедуры в разделе объявлений блоков PL/SQL. При объявлении хранимой процедуры можно использовать следующие параметры для указания области привилегий, которая ис­пользуется в Oracle при выполнении данной процедуры:

  • AUTHID CURRENT_USER. Если процедура создается с данной опцией, то Oracle выполняет ее, используя область привилегий вызывающего процедуру пользователя, включая роли. Для успешного выполнения процедуры вызывающий ее пользователь должен иметь привилегии, необходимые для доступа ко всем объектам базы данных, к которым имеются SQL-обращения в теле процедуры.

  • AUTHID DEFINER. Опция по умолчанию. Oracle выполняет процедуру, исполь­зуя область привилегий владельца процедуры, исключая роли. Для успешного выполнения процедуры ее владелец, должен иметь привилегии, необходимые для доступа ко всем объектам базы данных, к которым имеются SQL-обращения в теле хранимой процеду­ры.

Чтобы упростить управление привилегиями для пользователей приложений, при создании хранимой процедуры сле­дует применять используемую по умолчанию опцию AUTHID DEFINER. Этот способ позволяет давать привилегии не всем поль­зователям, которым приходится вызывать процедуру.

Приведенный ниже пример иллюстрирует создание и хранение уже известной нам процедуры printLine в базе данных Oracle:

Раскрыв в навигаторе узел Procedures, увидим процедуру printLine.

Теперь процедуру printLine хранится в базе и можно использовать ее в любой программе PL/SQL. Выполним блок PL/SQL, использующий процедуру printLine:

Для создания хранимой функции используется ко­манда CREATE FUNCTION. Функция описывается, как в блоке PL/SQL. Для нее нужно объявить тип возвращаемого значения, а в теле функции должны присутствовать один или несколько операторов RETURN для возвращения функцией ее значения. Рассмотрим при­мер создания и хранение функция orderTotal в базе данных Oracle:

Раскрыв в навигаторе узел Functions, увидим функцию orderSum.

Теперь введите следующий блок для расчета суммы заказов 1 и 2:

Пакеты

Пакет – группа процедур, функций и других PL/SQL-конструкций, которые хранятся в базе данных как единое целое. Пакеты полезны для создания группы из нескольких процедур и функций, относящихся к определенному приложению.

Пакет состоит из двух частей:

  • Спецификация пакета. Определяет интерфейс пакета. В ней объявляются переменные пакета, константы, курсоры, процедуры, функции и другие конструкции, которые не­обходимо сделать доступными для программ за пределами пакета (все, что объявлено в спецификации пакета, является общедоступным). Спецификация пакета объявляется с по­мощью SQL-команды CREATE PACKAGE.

  • Тело пакета. В теле определяются все общедоступные процеду­ры и функции, объявленные в спецификации. Тело пакета может включать определения других конст­рукций, не объявленных в спецификации. Такие конструкции являются частными (доступными только для программ внутри пакета). Тело пакета объявляется с помощью SQL-команды CREATE PACKAGE BODY.

Отделение спецификации пакета (интерфейса) от его тела позволяет модифицировать реализующую пакет логи­ку без нарушения зависимостей, которые опираются на API пакета.

Все переменные, константы и курсоры, объявленные в спецификации либо в теле пакета, вне подпрограммы считаются глобальными. В отличие от локальных переменных, констант и курсоров, объявленных внутри оп­ределенных процедур и функций, глобальные конструкции доступны всем процедурам и функциям пакета. Их состояние в течение сеанса остается постоянным независимо от подпрограмм пакета. Соглашение по объявлению глобальных перемен­ных (и других глобальных конструкций) пакета предпо­лагает использование префикса g_.

Рассмотрим создание простого пакета catMgmt, демонстрирующего функции, доступные паке­там PL/SQL. Сначала нужно создать спецификацию пакета:

Далее создайте тело пакета, используя приведенную ниже директиву.

Теперь введите анонимный блок PL/SQL, использующий процедуру insertCat пакета catMgmt для вставки новой строки в таблицу Catalogs:

Обратите внимание на то, что при ссылке на объект типа пакет (на глобальную переменную или подпрограмму) необходимо ис­пользовать точечную нотацию для идентификации объекта пакета по имени самого пакета.

Введите анонимный блок для изменения названия нового каталога на «Разное» с ис­пользованием процедуры updateCat пакета catMgmt.

Теперь введите анонимный блок PL/SQL для вы­полнения процедуры deleteCat пакета catMgmt, которая удаляет новую часть таблицыCatalogs.

В заключение введите анонимный блок для выво­да количества строк таблицы Catalogs, обработанных в текущем сеансе с помощью пакета catMgmt.

Процедура printCatProcessed показывает, что глобальная перемен­ная g_rowsProcessed сохраняет свое состояние независимо от обращений к отдельным подпрограммам пакета.

Команда EXECUTE представляет собой другой способ вы­полнения PL/SQL-подпрограмм. Вызывая функцию, необходимо создать переменную для присвоения ей возвращаемого функцией значения.