Язык PL/SQL - Иван Сергеевич Задворьев 2 стр.


В PL/SQL имеются скалярные и составные типы данных:

данные скалярных типов состоят из одного неделимого (атомарного) значения (логические значения, числа, даты, строки);

данные составных типов состоят из нескольких значений (записи и коллекции).

Скалярные типы данных PL/SQL

Объявления типов данных PL/SQL находятся в пакете STANDARD, находящемся в схеме пользователя SYS:

package STANDARD AUTHID CURRENT_USER is

type BOOLEAN is (FALSE, TRUE);

type DATE is DATE_BASE;

type NUMBER is NUMBER_BASE;

subtype FLOAT is NUMBER;  NUMBER(126)

subtype REAL is FLOAT;  FLOAT(63)

subtype INTEGER is NUMBER(38,0);

subtype INT is INTEGER;

subtype DEC is DECIMAL;

subtype BINARY_INTEGER is INTEGER range '-2147483647'..2147483647;

subtype NATURAL is BINARY_INTEGER range 0..2147483647;

type VARCHAR2 is NEW CHAR_BASE;

subtype VARCHAR is VARCHAR2;

subtype STRING is VARCHAR2;

Видно, что объявленные в пакете STANDARD типы данных PL/SQL либо соответствуют типам данных Oracle SQL (_BASE-типы), либо вводятся как их подтипы (subtype).

Отметим наличие типа данных BOOLEAN, которого нет в Oracle SQL. Значения типа BOOLEAN можно, например, использовать в коде следующего вида:

l_amount_negative_flag BOOLEAN := amount<0;

IF l_amount_negative_flag THENEND IF;

Существенным отличием типов данных PL/SQL и Oracle SQL является большая максимальная длина значений типов CHAR и VARCHAR2, предназначенных для представления строк фиксированной и переменной длины:

для VARCHAR2 в PL/SQL максимальная длина значений находится в диапазоне от 1 до 32 767 байт (в Oracle SQL до версии Oracle 12c максимальная длина VARCHAR2 была до 4000 байт, в Oracle 12c она была увеличена также до 32 767 байт);

для CHAR в PL/SQL максимальная длина значений находится в диапазоне от 1 до 32 767 байт (в Oracle SQL до версии Oracle 12c максимальная длина CHAR была до 2000 байт, в Oracle 12c она была увеличена также до 32 767 байт).

Записи PL/SQL

Записи PL/SQL относятся к составным типам данных и определяются как наборы атрибутов, связанных определенными отношениями. Атрибуты записи могут быть как скалярных типов данных, так и других составных типовдругими записями и коллекциями.

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

DECLARE

TYPE t_person IS RECORD

(name VARCHAR2 (100),

secname VARCHAR2 (100),

surname VARCHAR2 (100),

born DATE);

l_person t_person;

BEGIN

l_person.surname := 'Ильин';

l_person.name := 'Виктор';

l_person.secname := 'Семенович';

l_person.born := TO_DATE('07.08.1969','dd.mm.yyyy');

print(l_person);

END;

Назначение записей PL/SQL:

считывание в записи PL/SQL строк результирующих выборок SQL-запросов (при объявлении записей PL/SQL на основе таблиц и курсоров с помощью атрибута %ROWTYPE);

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

Компактность и расширяемость исходного кодаосновное преимущество от использования записей PL/SQL. Сравните два варианта вызова процедуры печати сведений о человекес одним параметром-записью PL/SQL и с несколькими параметрами скалярных типов данных:

print(l_person) и print(l_name, l_secname, l_surname, l_born)

Первый вариант вызова выглядит более компактным. Кроме того, если появится необходимость обрабатывать новые сведения о человеке, например, ИНН и СНИЛС, то для второго варианта во все вызовы процедуры print по всему коду понадобится дописать по два новых параметра. Если же передавать описание человека в виде записи PL/SQL, то потребуется только добавить новые атрибуты в объявление типа t_person. Вносить изменения в заголовок функции print и в ее вызовы по исходному коду не потребуется. Тем самым с помощью использования записей PL/SQL обеспечивается расширяемость исходного кода.

Приведем основные правила работы с записями PL/SQL:

в определении атрибутов записей могут быть указаны ограничения NOT NULL и заданы значения атрибутов по умолчанию;

присвоение записи NULL присваивает NULL всем ее атрибутам;

чтобы сравнить две записи на равенство или неравенство нужно последовательно попарно сравнить значения всех атрибутов.

Так как записи PL/SQL похожи на строки таблиц, то особенно выпукло преимущества их использования для обеспечения компактности и расширяемости кода проявляются при выполнении предложений SQL в PL/SQL. Одна строка таблицыодна запись PL/SQL. Строки таблиц «живут» в базе данных, записи PL/SQL «живут» в программах. Строку таблицы можно одной командой считать в запись PL/SQL, запись PL/SQL можно одной командой вставить как строку таблицы, то есть обеспечивается движение данных в обоих направлениях. В PL/SQL также есть специальные языковые конструкции, которые позволяют перемещать между базой данных и программой PL/SQL не отдельные записи PL/SQL и строки таблиц, а их множества. И все это делается очень компактноодной-двумя строками кода PL/SQL.

Объявление переменных с привязкой

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

Существует два вида привязки переменных:

скалярная привязка (c помощью атрибута %TYPE переменная объявляется с типом данных указанного столбца таблицы);

привязка к записи (с помощью атрибута %ROWTYPE объявляется переменная-запись PL/SQL с атрибутами по числу столбцов указанной таблицы или курсора).

Рассмотрим пример. Пусть в базе данных имеется таблица tab1 со столбцами at1 типа DATE и at2 типа VARCHAR2(20). Тогда в коде PL/SQL можно объявить переменные следующим образом:

l_tab1 tab1%ROWTYPE;

l_at1 tab1.at1%TYPE;

Переменная l_tab1 будет являться записью PL/SQL с двумя атрибутами at1, at2, типы данных которых будут такими же, как типы данных столбцов at1, at2 таблицы tab1, то есть DATE и VARCHAR2(20) соответственно. Переменная l_at1 будет иметь тип данных, такой же, как у столбца at1, то есть date.

Преимущества объявления переменных с привязкой:

автоматически выполняется синхронизация со схемами таблиц;

компактный расширяемый код для считывания строк результирующих выборок SQL-запросов без перечисления столбцов.

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

Приведем конкретный пример. В базе данных CRM-системы была таблица clients, в которой имелся столбец inn. На момент разработки системы клиентами могли быть только юридические лица, у которых длина ИНН составляет 10 символов. Со временем компания стала обслуживать и физических лиц, у которых длина ИНН 12 символов. Администратор базы данных изменил тип данных столбца inn таблицы clients с VARCHAR2(10) на VARCHAR2(12) и в таблице стал появляться строки с длинными ИНН. Так как в коде PL/SQL все переменные для работы с ИНН были объявлены как VARCHAR2(10), то при считывании из базы данных ИНН физических лиц в программах PL/SQL стали происходить ошибки. Если бы переменные для ИНН в свое время были объявлены с привязкой к столбцу inn с помощью атрибута %TYPE, то они автоматически «расширились» бы сами и ошибок на стадии выполнения не происходило бы.

Без перечисления столбцов результирующих выборок SQL-запросов пишется очень компактный код вида

l_person person%ROWTYPE;

SELECT * INTO l_person FROM person WHERE id=13243297;

print(l_person);

SQL-запрос выбирает все столбцы таблицы person, и у объявленной с помощью %ROWTYPE переменной l_person будет ровно столько же атрибутов, сколько столбцов у таблицы person, с такими же именами и типами данных, в том же порядке следования. Значения всех столбцов считываемой строки таблицы присвоятся соответствующим атрибутам записи PL/SQL. Если в таблице person в будущем появится новый столбец, он автоматически «подхватится» и SQL-запросом (SELECT *) и объявлением переменной l_person в программе PL/SQL. Никаких изменений в код вносить не потребуется, автоматическая перекомпиляция программы произойдет при первом обращении к ней.

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

Структура программы PL/SQL

Структура блока

В PL/SQL, как и в большинстве процедурных языков программирования, наименьшей единицей группировки исходного кода является блок. Он представляет собой фрагмент кода, определяющий границы выполнения кода и области видимости для объявлений. Блоки могут вкладываться друг в друга.

Разделы блока PL/SQL

Блок PL/SQL состоит из четырех разделов:

раздел заголовка;

раздел объявлений;

исполняемый раздел;

раздел обработки исключений.

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

Синтаксически блок PL/SQL выглядит следующим образом:

раздел заголовка

DECLARE

раздел объявлений

BEGIN

исполняемый раздел

EXCEPTION

раздел обработки исключений

END;

В разделе заголовка указываются:

тип блока (процедура, функция);

имя блока (имя процедуры, функции);

имена параметров, их типы данных и режимы передачи значений.

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

Ключевые слова BEGIN и END в языке PL/SQL являются операторными скобками, подобными символам { и } в других языках программирования и отмечают начало исполняемого раздела и конец блока. Каждая команда в PL/SQL должна завершаться точкой с запятой (символом ; ).

Виды блоков PL/SQL

В PL/SQL есть два вида блоков:

именованные блоки (с разделом заголовка);

анонимные блоки (без раздела заголовка).

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

именованные блоки хранимых в базе данных программ (процедур, функций, пакетов и триггеров);

именованные блоки в разделах объявлений других блоков (анонимных или именованных).

Хранимые программы (stored programs) являются объектами базы данных Oracle и создаются DDL-командой CREATE, после которой записывается именованный блок PL/SQL. Имя блока, указанное в разделе заголовка, будет являться именем объекта базы данных.

Анонимные блоки (anonymous blocks) раздела заголовка не имеют. Если блок не имеет раздела заголовка, то он не имеет и имени, которое в этом разделе указывается, поэтому такие блоки и называются анонимными.

Анонимные блоки либо вкладываются в другие блоки, либо хранятся в виде текстовых файлов-сценариев. В последнем случае анонимные блоки, как правило, используются для вызова хранимых программ или для автоматизации задач администрирования баз данных.

Анонимный блок-сценарий file1.sql

Вложенные анонимные блоки

в именованном блоке хранимой программы

DECLARE

i INTEGER;

 именованный блок процедуры proc1

 в разделе анонимного блока

PROCEDURE proc1 IS

BEGIN

NULL;

END;

BEGIN

 вызов процедуры proc1

proc1;

END;

 именованный блок процедуры proc2

CREATE PROCEDURE proc2 AS

BEGIN

 родительский анонимный блок,

 вложенный в именованный proc2:

DECLARE

BEGIN

 еще один анонимный блок

 вложенный в родительский:

DECLARE

BEGIN

NULL;

END;  конец вложенного блока

END;  конец родительского блока

END; конец именованного блока proc2

Комментарии

В любом месте исходного кода на PL/SQL могут быть комментарии, однострочные и многострочные.

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

Многострочный комментарий размещается между начальным (/*) и конечным (*/) ограничителями. Вложение многострочных комментариев друг в друга не допускается.

Тема комментирования исходного кода заслуживает отдельного рассмотрения. Авторы книги являются сторонниками следующего принципа: «Комментируйте неочевидные участки кода. Не комментируйте очевидные».

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

Переменные и константы PL/SQL

Приведем пример анонимного блока, в котором объявлены одна константа и две переменные, а в исполняемом разделе выполняются действия по вычислению натуральных логарифмов чисел 2 и 3.

/* Вычисление

двух логарифмов */

SQL> DECLARE

2 header1 CONSTANT VARCHAR2(20) := 'Логарифм двух равен ';

3 header2 CONSTANT VARCHAR2(20) := 'Логарифм трех равен ';

4 arg INTEGER := 2;

5исполняемый раздел

6 BEGIN

7 DBMS_OUTPUT.PUT_LINE(header1||LN(arg));

8 arg := arg+1;

9 DBMS_OUTPUT.PUT_LINE(header2||LN(arg));

10 END;

11 /

Логарифм двух равен .6931471805599453094172321214581765680782

Логарифм трех равен 1.09861228866810969139524523692252570465

PL/SQL procedure successfully completed.

В разделе объявлений можно объявлять как переменные, так и константы (с помощью ключевого слова CONSTANT). Константа отличается от переменной тем, что ее значение нельзя изменять после объявления. Если указать константу в левой части оператора присваивания и т. п., то это будет определено как ошибка еще на этапе компиляции. Переменным присваивать значения можно в любом разделе, в том числе прямо при ее объявлении в разделе объявлений. По умолчанию переменная инициализируется «пустым» значением NULL.

Имена констант, переменных, пользовательских типов данных в грамматике PL/SQL называются идентификаторами. К идентификаторам предъявляются следующие требования:

идентификатор должен состоять только из букв, цифр и символов _$#

идентификатор должен начинаться с буквы;

длина идентификатора должна быть до 30 символов;

идентификатор не должен быть зарезервированным словом.

Примеры недопустимых идентификаторов:

2_name (начинается не с буквы, правильноl_second_name);

l_exchange_rate_on_current_date (длина свыше 30 символов).

Рекомендуется блокам PL/SQL, пользовательским типам данных, переменным и константам давать имена, соответствующие некоторому соглашению об именовании.

В языке PL/SQL переменные, константы и пользовательские типы данных являются локальными для блока, в котором они объявлены. Когда выполнение блока будет завершено, все эти объекты внутри программы становятся недоступными. Можно сказать, что у каждого объявленного в программе PL/SQL элемента имеется некоторая область видимостиучасток программы, в котором можно ссылаться на этот элемент (блок, в котором элемент объявлен, и все вложенные в него блоки).

Структуры управления вычислениями

Известно, что для реализации алгоритмов на процедурном языке программирования требуется наличие в нем трех следующих структур управления вычислениями, причем должна быть возможность вкладывать все структуры друг в друга произвольным образом:

последовательность команд (выполнение команд согласно их упорядоченности);

выбор (проверка условия и выполнение той или иной последовательности команд в зависимости от истинности или ложности условия);

повторение (выполнение последовательности команд до тех пор, пока условие повторения принимает истинное значение).

Рис. 1. Структуры управления вычислениями.

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

Условные команды и команды перехода

В PL/SQL к условным командам относятся команды IF и CASE, переходы реализуются командами GOTO и NULL.

Условная команда IF

Условная команда IF позволяет проверить заданное логическое условие и, в зависимости от результатов проверки (TRUE, FALSE или UNKNOWN), выполнить различные ветви кода. В PL/SQL имеется три формы команды IF:

Назад Дальше