Рис. 11.1. Список встроенных типов PL/SQL

advertisement
Структура программы на PL/SQL
PL/SQL - это процедурный блочно-структурированный язык. Он представляет собой
расширение языка SQL и предназначен для работы с СУБД Oracle.
PL/SQL предоставляет разработчику приложений и интерактивному пользователю
следующие основные возможности:









реализация подпрограмм как отдельных блоков, в том числе использование
вложенных блоков;
создание пакетов, процедур и функций, хранимых в базе данных;
предоставление интерфейса для вызова внешних процедур;
поддержка как типов данных SQL, так и типов, вводимых в PL/SQL;
применение явного и неявного курсора, а также оператора цикла FOR для курсора;
введение у переменных PL/SQL и курсоров атрибутов, которые позволяют
ссылаться на тип данных или структуру элемента;
введение типов коллекций и объектных типов;
поддержка набора операторов управления и операторов цикла;
реализация механизма обработки исключений.
Основной программной единицей PL/SQL является блок, который может содержать
вложенные блоки, называемые иногда подблоками.
Блок позволяет объединять объявления и операторы, связанные общей логикой; может
быть анонимным и именованным.
Блок состоит из трех основных частей:



секция объявлений (необязательная часть);
тело блока;
обработчики исключений (необязательная часть).
[ <<label_name>> ] [DECLARE
]
BEGIN
[EXCEPTION
]
END [label_name];
Метка блока
Секция объявлений
Тело блока
Обработчики исключений
PL/SQL не чувствителен к регистру, кроме строковых переменных и констант.
Каждая конструкция PL/SQL должна заканчиваться символом ;.
Одна конструкция может быть расположена на нескольких строках.
Работа с процедурами и функциями
CREATE OR REPLACE FUNCTION FName (V1 TYPE, V2 TYPE, ...) RETURN TYPE IS
...
BEGIN
...
END FName;
--CREATE OR REPLACE PROCEDURE TEST_POZ(
PR_A IN NUMBER,
PR_B IN NUMBER,
PR_C IN VARCHAR2,
PR_D IN VARCHAR2
)
IS
BEGIN
NULL;
END TEST_POZ;
Типы данных
Язык PL/SQL поддерживает следующие категории типов:


встроенные типы данных, включая коллекции и записи;
объектные типы данных.
Встроенные типы данных
Встроенные типы данных
На рис. 11.1 приведен список встроенных типов PL/SQL.
Рис. 11.1. Список встроенных типов PL/SQL
Скалярные типы описывают простые значения, не имеющие внутренних составляющих.
Составные типы описывают структуры, в которых имеются внутренние компоненты.
Ссылочные типы содержат значения. LOB типы содержат значения, называемые
локаторами, которые определяют расположение больших объектов хранимых данных
(например, графические файлы).
В следующей таблице приведено описание некоторых типов данных языка PL/SQL.
Синтаксис
Диапазон значений
Числовые типы
BINARY_INTEGER PLS_INTEGER (целое со
знаком)
-2147483647 .. 2147483647. Тип PLS_INTEGER
требует меньше памяти и обрабатывается
быстрее, чем другие числовые типы
NUMBER[(precision,scale)] (с плавающей
точкой)
1.0E-130 .. 9.99E125
NUMERIC (с фиксированной точкой)
точность до 38 десятичных знаков
FLOAT (с плавающей точкой)
точность до 38 десятичных знаков
REAL (с плавающей точкой)
точность до 18 десятичных знаков
Символьные типы
CHAR[(maximum_length)] (для строк
постоянной длины) LONG (для строк
переменной длины)
до 32767 байт Для столбца базы данных
максимальный размер типа CHAR составляет 2000
байтов, а типа LONG - до 2 Гб
RAW(maximum_length) LONG RAW (для
двоичных данных или строк байтов)
до 32767 байт Для столбца базы данных типа RAW
максимальный размер - 2000 байт.
VARCHAR2 (maximum_length) (для строк
символов переменной длины)
до 32767 байт
Все встроенные типы данных являются базовыми типами.
Любой базовый тип PL/SQL определяется как набор значений и набор операций,
выполнимых над этими значениями.
Язык PL/SQL позволяет определять новые подтипы как подмножество значений
некоторого базового типа с тем же набором операций. Подтип не вводит никаких
дополнительных операций над данными и не определяет никакого нового типа.
Определение подтипа может иметь следующее формальное описание:
SUBTYPE subtype_name IS base_type;
В пакете STANDARD базы данных Oracle, автоматически подключаемом для любого
блока, определено несколько подтипов.
Пользователь может определить свой тип как некоторый подтип в секции объявлений
блока, подпрограммы или пакете PL/SQL.
Например:
DECLARE
SUBTYPE MyDate IS DATE;
- Основан на типе DATE
TYPE MyRec IS RECORD (time1 INTEGER,
time2 INTEGER);
SUBTYPE MyInterval IS MyRec;
- Основан на типе RECORD
SUBTYPE ID_N IS tbl1.f1%TYPE;
- Основан на типе столбца
Типы, используемые как базовые, не могут содержать ограничений длины. Для создания
пользовательского типа с ограничением длины предварительно объявляется переменная
такого типа и уже на ее основе определяется пользовательский тип.
Например:
DECLARE
var1 VARCHAR2(6);
- Объявление переменной
- с ограничением длины
SUBTYPE string_6 IS var1%TYPE;
- Объявление
LOB-типы
LOB-типы используются для хранения больших объектов (Large Object). Стандарт SQL-99
ввел поддержку LOB-типов для расширенного уровня соответствия. Однако в Oracle
реализован более полный набор LOB-типов.
В Oracle8 позволяется хранить данные LOB-типа до 4 Гбайт.
Типы LOB от типа LONG отличаются, главным образом, тем, что при выборе значения
любого LOB-типа посредством оператора SELECT возвращается указатель, а не само
значение; кроме того, типы LOB могут быть и внешними.
Oracle поддерживает следующие четыре типа для больших объектов:




BFILE - для внешнего двоичного файла;
BLOB - для внутреннего двоичного объекта;
CLOB - для внутреннего символьного объекта;
NCLOB - для внутреннего символьного объекта, учитывающего национальный набор
символов.
Любой объект LOB состоит из двух частей: данных и указателя на эти данные,
называемого локатором.
Типы BLOB, CLOB или NCLOB могут использоваться как для столбца базы данных, так и
для переменной PL/SQL.
Для загрузки объекта LOB предусмотрен пакет PL/SQL DBMS_LOB.
Пакет DBMS_LOB для работы с LOB-типами содержит процедуры и функции, некоторые
из которых приведены в следующей таблице.
Синтаксис
Описание
APPEND (d1,d2)
Добавляет d2 к d1
COMPARE(d1,d2,n,pos1,pos2)
Сравнивает n байт значений d1 и d2
COPY (d,s,n,dp,sp)
Копирует n байт из d в s.
FILEOPEN (bdata,m)
Открывает объект типа BFILE в режиме, указанном
параметром m
LOADFROMFILE
(bdata1,data2,n,pos1,pos2)
Копирует n байт объекта типа BFILE bdata1 в любой объект
LOB data2
GETLENGTH (data)
Возвращает длину указанного объекта LOB
READ (data,n,pos,buf)
Читает из объекта data n байт
WRITE (data,n,pos,buf)
Копирует из буфера buf n байт
EMPTY_CLOB (), EMPTY_BLOB ()
Создают "пустой" объект указанного типа
Приведение типов
PL/SQL поддерживает явное и неявное приведение типов:явное приведение типов
выполняется с помощью встроенных функций, а неявное - посредством PL/SQL (если это
возможно) при присвоении значения одного типа.
Значения переменных различных типов могут присваиваться друг другу в том случае,
если они образованы из одного базового типа
Объявление переменных и констант
Переменные могут иметь тип данных SQL или тип данных PL/SQL.
Переменная объявляется в секциях объявлений блока PL/SQL, подпрограммы или пакета.
Для объявления переменной после ее идентификатора следует указывать любой
доступный тип данных.
Объявление переменной в PL/SQL может иметь следующие формы:
var_name
var_name
var_name
var_name
var_name
var_name
var_name
var_name
type;
type := expr;
type DEFAULT expr;
type NOT NULL := expr;
type_var%TYPE;
type_var%TYPE := expr;
user.table.type_col%TYPE;
user.table.type_col%TYPE := expr;
Одновременно, при объявлении переменной, она может быть проинициализирована
значением соответствующего типа. Выражение, находящееся справа от знака
присваивания, может использовать ранее объявленные и проинициализированные
переменные или константы. PL/SQL требует, чтобы используемая ссылка была описана в
программе выше места ее применения.
При объявлении переменной вместо оператора присваивания может указываться
ключевое слово DEFAULT.
Объявляемая переменная может быть определена как NOT NULL. Такой переменной в
дальнейшем нельзя присвоить значение NULL.
Переменным можно присваивать значения двумя способами - как с помощью оператора
присваивания, так и как INTO-переменной, указываемой в запросе.
При объявлении константы после идентификатора должно быть указано ключевое слово
CONSTANT, а после идентификатора типа - указан оператор присваивания и значение
константы.
Объявление константы может иметь следующее формальное описание:
const_name CONSTANT type :=value;
Например:
val_real CONSTANT REAL := 5000.00;
Символьные константы заключаются в одинарные кавычки.
Атрибуты %TYPE и %ROWTYPE
Атрибут %TYPE позволяет объявлять переменную типа, соответствующего:


типу другой переменной;
типу столбца базы данных.
Например:
var1 REAL(14,2);
var2 var1%TYPE;
- Переменная var2 будет иметь тип как var1
var_f1 user1.tbl1.f1%TYPE;
/* Переменная var_f1 будет иметь тот же
тип, что и поле f1 таблицы tbl1
пользователя user1*/
Атрибут %ROWTYPE позволяет объявлять переменную типа "запись", соответствующую
строке таблицы. Переменная такого типа имеет поля, совпадающие с полями таблицы по
имени и типу.
Такой тип значительно облегчает программирование операций со строками, позволяя
выполнять выборку строки целиком в одну переменную типа "запись", а также
предотвращает необходимость перепрограммирования блоков в случае изменения
структуры таблицы.
Значения переменным, определенным с использованием атрибута %ROWTYPE, могут
быть назначены как присваиванием значения одной записи другой записи, так и как INTOпеременным оператора SELECT.
Например:
DECLARE
tbl1_rec1 tbl1%ROWTYPE;
- Для строки из таблицы tbl1
tbl1_rec2 tbl1%ROWTYPE;
CURSOR c1 IS SELECT * FROM tbl1;
emp_rec2 c1%ROWTYPE;
- Для строки курсора с1,
- созданного из таблицы tbl1
emp_rec3 с1%ROWTYPE;
BEGIN
SELECT * INTO tbl1_rec1 FROM tbl1
WHERE tbl1.f1=1;
emp_rec2 := emp_rec1;
- Присвоение значения всем полям записи
END
Переменная типа "запись" без квалификации именами полей может использоваться только
для выборки значений, но ее нельзя применять для вставки или обновления значений
строки. В SQL-операторе вставки или обновления для каждого столбца таблицы должно
быть указано значение поля записи.
Операторы управления языка PL/SQL
Любой оператор языка PL/SQL, используемый для управления ходом выполнения
программы, может относиться к одной из следующих групп операторов:



операторы выбора:
o IF-THEN-END IF;
o IF-THEN-ELSE-END IF;
o IF-THEN-ELSIF-END IF;
операторы цикла:
o LOOP-END LOOP;
o WHILE-LOOP-END LOOP;
o FOR-LOOP-END LOOP;
o EXIT;
o EXIT WHEN;
операторы безусловного перехода:
o GOTO;
o NULL;
o <<labels>>.
Операторы выбора
Язык PL/SQL реализует три формы оператора выбора, которые могут иметь следующее
формальное описание:
- 1 форма:
IF condition THEN sequence_of_statements;
END IF;
- 2 форма:
IF condition THEN sequence_of_statements1;
ELSE sequence_of_statements2; END IF;
- 3 форма:
IF condition1 THEN sequence_of_statements1;
ELSIF condition2 THEN sequence_of_statements2;
- Ключевое слово ELSIF
- может повторяться многократно
ELSIF condition3 THEN sequence_of_statements3;
ELSE sequence_of_statements4; END IF;
- Ключевое слово ELSE может отсутствовать
Последовательность операторов (sequence_of_statements) может включать другой
вложенный оператор выбора.
Например:
BEGIN
IF f3 = 'abc' THEN
UPDATE tbl1 SET f2 = f2 + 50
WHERE f1 = 1;...
ELSE
UPDATE tbl1 SET f2 = f2 + 70
WHERE f1 = 1;......
END IF;
Операторы цикла
Оператор цикла позволяет многократно выполнять одну последовательность операторов.
Язык PL/SQL реализует три формы операторов цикла, которые могут иметь следующее
формальное описание:
- 1 форма - выход из цикла должен быть указан оператором выхода:
LOOP sequence_of_statements; END LOOP;
LOOP sequence_of_statements;
EXIT WHEN boolean_expression;
- Оператор выхода из цикла
END LOOP;
<<label_of_loop>> - Метка цикла
LOOP sequence_of_statements;
END LOOP label_of_loop;
- Конец помеченного цикла
- 2 форма - цикл выполняется, пока условие истинно:
WHILE condition LOOP sequence_of_statements;
END LOOP;
- 3 форма - цикл выполняется заданное число раз:
FOR counter IN [REVERSE]
lower_bound..higher_bound
LOOP sequence_of_statements;
END LOOP;
Для выхода из цикла используются операторы EXIT и EXIT-WHEN, а для выхода из блока
PL/SQL - оператор RETURN.
Цикл FOR выполняется заданное число раз, пока значение счетчика цикла принадлежит
указанному диапазону. Значение счетчика цикла FOR проверяется до выполнения цикла.
Диапазон значений может быть указан через символ .. (две точки). Параметр REVERSE
определяет обратный отсчет для переменной цикла. Диапазон значений может быть задан
выражениями, но не должен изменяться внутри цикла.
Например:
- 1. цикл LOOP:
LOOP
FETCH c1 INTO rec1;
EXIT WHEN c1%NOTFOUND;
- Выход из цикла, если нет
- больше строк
END LOOP;
- 2. цикл WHILE:
WHILE c1 >= 50 LOOP
- ...
c1:= c1 - 1;
END LOOP;
Операторы безусловного перехода
Оператор GOTO используется для безусловного перехода на заданную метку. Этот
оператор может применяться для перехода во внешний блок, но его нельзя использовать
для перехода во вложенный цикл или подблок.
Метка указывается в двойных угловых кавычках и используется для определения точки в
программе, на которую может быть выполнен безусловный переход, или для
квалификации имени переменной.
Оператор NULL - это пустой оператор, используемый для выполнения роли заглушки в
теле функции или процедуры, или как оператор, перед которым можно указать метку.
Например:
DECLARE
i1 INTEGER;
BEGIN
FOR i IN 1..10 LOOP
IF i1=1 THEN
GOTO end_loop;
- Переход на конец цикла
END IF;
<<end_loop>>
NULL;
- Оператор указывается для
- использования метки
END LOOP;
END;
Записи
Записью называется набор элементов, хранимых в полях записи. Каждое поле имеет свое
имя и тип.
Записи нельзя сравнивать на равенство или неравенство и на эквивалентность значению
NULL.
Запись может быть объявлена на базе существующей структуры таблицы или как новый
тип.
Для объявления записи, имеющей структуру, соответствующую строке таблицы базы
данных, используется атрибут %ROWTYPE.
Объявление нового типа "запись" может иметь следующее формальное описание:
TYPE type_name IS RECORD
(field_declaration
[, field_declaration]...);
Описание поля (field_declaration) указывается как:
field_name field_type
[[NOT NULL] {:= | DEFAULT} expression]
Параметр type_name задает имя определяемого типа; field_type указывает тип поля как
любой тип PL/SQL за исключением REF CURSOR; expression определяет значение
инициализации.
Как и для коллекций, для создания записи следует сначала определить тип RECORD, а
затем объявить запись данного типа.
Тип "запись" существует только на время выполнения программы и не может быть
сохранен в базе данных в отличие от типов TABLE и VARRAY.
Для доступа к любому полю записи используется следующая нотация:
record_name.field_name. Если field_name также является записью, то для доступа к его
вложенному полю используется та же нотация: record_name.field_name.field1_name и т.д.
В выражениях языка PL/SQL выполнять присваивание значения можно как отдельно
полю, так и всей записи.
Выполнять присвоение значения всей записи можно двумя способами:


использовать в качестве присваиваемого значения запись того же типа;
задать запись в качестве INTO-переменной в SQL-операторе SELECT или FETCH.
Например:
DECLARE
- Определение типа
TYPE T_rec IS RECORD (
f1 tbl1.f1%TYPE,
f2 VARCHAR2(15),
f3 REAL(7,2));
- Тип на основе строки таблицы
rec3 tbl1%ROWTYPE;
- Объявление записи
rec1 T_rec;
f_sum1 REAL;
FUNCTION sum_f3 (n INTEGER)
RETURN T_rec IS
rec2 T_rec;
BEGIN
- :
- Функция возвращает значение
- типа запись
RETURN rec2;
END;
BEGIN
- Вызов функции
rec1 := sum_f3(4);
f_sum1 := sum_f3(4).f3;
SELECT * INTO rec3 FROM tbl1
WHERE f1 = 1;
END;
Запрос одной строки из базы данных
DECLARE
empname
VARCHAR2(200);
BEGIN
SELECT ename
INTO empname
FROM scott.emp
WHERE empno = 7439;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.put_line('No records found!');
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.put_line('Found more than one string!');
END;
Запрос нескольких строк из базы данных
Для запроса нескольких строк следует использовать курсоры PL/SQL. Под курсором
подразумевается указатель на очередную строку в результатах запроса. Открытие и
закрытие курсора осуществляется операторами OPEN и CLOSE. Считывание значений, на
которые указывает курсор, и его перевод на следующую строку осуществляется
оператором FETCH.
Считывание данных из запроса оформляется как цикл. Когда курсор дойдёт до конца
результатов запроса, очередной вызов оператора FETCH не считает новых данных, а
атрибут <имя_курсора>%NOTFOUND принимает значение TRUE. Это событие используется
для прерывания работы цикла.
Обработчиков исключений в этом случае не требуется, если данные не будут найдены, то
цикл не будет выполнен ни разу.
DECLARE
empname VARCHAR2(200);
CURSOR c1 IS
SELECT ename
FROM scott.emp;
BEGIN
OPEN c1;
LOOP
FETCH c1 INTO empname;
EXIT WHEN c1%NOTFOUND;
-- работа со значением empname
END LOOP;
CLOSE c1;
END;
Использование указателей на курсоры
DECLARE
TYPE GenericCursor IS REF CURSOR;
с1 GenericCursor;
empname VARCHAR2(200);
BEGIN
OPEN c1 FOR SELECT ename FROM scott.emp;
LOOP
FETCH c1 INTO empname;
EXIT WHEN c1%NOTFOUND;
-- работа со значением empname
END LOOP;
CLOSE c1;
END;
Использование связанных переменных
FUNCTION get_employee_name (empid INTEGER, empcity VARCHAR2) RETURN VARCHAR2
IS
TYPE GenericCursor IS REF CURSOR;
c1 GenericCursor;
empname VARCHAR2(200);
BEGIN
OPEN c1 FOR 'SELECT ename FROM employees WHERE id = :id AND city = :city'
USING empid, empcity;
-- цикл не используется, так как запрос вернёт не более одной строки
FETCH c1 INTO empname;
CLOSE c1;
RETURN empname;
END get_employee_name;
Неявное определение курсора в цикле
DECLARE
BEGIN
FOR rec IN (SELECT id, ename FROM employees) LOOP
DBMS_OUTPUT.put_line(rec.id || ': ' || rec.ename);
END LOOP;
END;
Коллекции
Коллекцией называется упорядоченная группа элементов одного типа. Язык PL/SQL
поддерживает три вида коллекций:



вложенные таблицы (nested tables);
индексированные таблицы;
varray-массивы (variable-size arrays).
Доступ к любому элементу вложенной таблицы или varray-массива осуществляется по его
индексу, который указывается в скобках после имени переменной типа коллекции.
Коллекция может быть передана в качестве параметра. Коллекцию можно использовать:


для обмена с таблицами баз данных и столбцами данных;
для передачи столбца данных из приложения клиента в хранимую процедуру или
обратно.
Для создания коллекции следует определить тип коллекции - TABLE или VARRAY - и
объявить переменную этого типа. Определение типа выполняется в секции объявлений
блока PL/SQL, подпрограммы или пакета.
Вложенные таблицы
Определение типа вложенной таблицы может иметь следующее формальное описание:
TYPE type_name IS TABLE OF
element_type [NOT NULL];
Параметр type_name указывает имя определяемого типа, а element_type - это любой
допустимый тип данных PL/SQL, исключая некоторые типы, в том числе VARRAY,
TABLE, BOOLEAN, LONG, REF CURSOR и т.п.
Вложенную таблицу можно рассматривать как одномерный массив, в котором индексами
служат значения целочисленного типа в диапазоне от 1 до 2147483647. Вложенная
таблица может иметь пустые элементы, которые появляются после их удаления
встроенной процедурой DELETE. Вложенная таблица может динамически увеличиваться.
Пример.
DECLARE
TYPE TYP_REC IS RECORD
(
num
number
,vname varchar2(30)
);
TYPE rec_table_type IS TABLE OF TYP_REC ;
my_tab rec_table_type;
BEGIN
my_tab := rec_table_type();
my_tab.EXTEND;
my_tab(1).num := 21;
my_tab(1).vname := 'норма';
my_tab.EXTEND;
my_tab(2).num := 21;
my_tab(2).vname := 'норма1';
my_tab.EXTEND;
my_tab(3).num := 21;
my_tab(3).vname := 'норма1';
DBMS_OUTPUT.PUT_LINE('my_tab(1) is '||my_tab(1).num||' '||my_tab(1).vname);
For i IN my_tab.FIRST .. my_tab.LAST Loop
dbms_output.put_line( 'Line = ' || my_tab(i).num ) ;
dbms_output.put_line( 'Code = ' || my_tab(i).vname ) ;
End loop;
END;
Индексированные таблицы
Индексированные таблицы позволяют работать со столбцами как с единой переменной массивом.
Определение индексированной таблицы (index-by tables) может иметь следующее
формальное описание:
TYPE type_name IS TABLE
OF element_type [NOT NULL]
INDEX BY BINARY_INTEGER|pls_integer|VARCHAR2(size);
Индексированная таблица - это вариант вложенной таблицы, в которой элементы могут
иметь произвольные целочисленные значения индексов. Такой тип данных очень удобен,
если в качестве индекса использовать значение первичного ключа.
Пример. Формирование листа сотрудников сгруппированного по двум параметрам:
департаменту и кварталу принятия на работу
DECLARE
TYPE list_aa IS TABLE OF VARCHAR2(2000)
INDEX BY VARCHAR2(256);
v_list_aa list_aa;
CURSOR c_dept IS
SELECT deptNo
FROM dept
ORDER BY deptNo;
CURSOR c_emp IS
SELECT eName, deptNo, TO_CHAR(hireDate,'q') q_nr
FROM emp;
v_subscript_tx VARCHAR2(256);
BEGIN
FOR r_dept IN c_dept LOOP
v_list_aa(r_dept.deptNo||'|1'):='Q1
Dept#'||r_dept.deptno||':';
v_list_aa(r_dept.deptNo||'|2'):='Q2
Dept#'||r_dept.deptno||':';
v_list_aa(r_dept.deptNo||'|3'):='Q3
Dept#'||r_dept.deptno||':';
v_list_aa(r_dept.deptNo||'|4'):='Q4
Dept#'||r_dept.deptno||':';
END LOOP;
FOR r_emp IN c_emp LOOP
v_list_aa(r_emp.deptNo||'|'||r_emp.q_nr):=
v_list_aa(r_emp.deptNo||'|'||r_emp.q_nr)||'
'||r_emp.eName;
END LOOP;
v_subscript_tx:=v_list_aa.FIRST;
LOOP
DBMS_OUTPUT.put_line(v_list_aa(v_subscript_tx));
v_subscript_tx:=v_list_aa.next(v_subscript_tx);
EXIT WHEN v_subscript_tx IS NULL;
END LOOP;
END;
VARRAY-массивы
Определение типа Varray-массива может иметь следующее формальное описание:
TYPE type_name IS
{VARRAY | VARYING ARRAY} (size_limit)
OF element_type [NOT NULL];
Параметр type_name указывает имя определяемого типа, size_limit - максимальное
количество элементов, а element_type - это любой допустимый тип данных PL/SQL,
исключая некоторые типы, такие как VARRAY, TABLE, BOOLEAN, LONG, REF
CURSOR и т.п.
Если типом элемента является тип "запись", то каждое поле записи должно быть
скалярного или объектного типа.
Максимальное количество элементов в Varray-массиве указывается при определении типа
и не может изменяться динамически. Доступ к каждому элементу Varray-массива
осуществляется по индексу. Varray-массивы можно передавать в качестве параметров.
Varray-массивы не могут иметь пустот, так как для них нет операции удаления
произвольного элемента массива.
Пример.
DECLARE
TYPE d1 IS VARRAY(365) OF DATE;
TYPE rec1 IS
RECORD (v1 VARCHAR2(10),
v2 VARCHAR2(10));
- Массив записей
TYPE arr_rec IS VARRAY(250) OF rec1;
- Вложенная таблица
TYPE F1T1 IS TABLE OF tbl1.f1%TYPE;
CURSOR c1 IS SELECT * FROM tbl1;
- Массив записей,
- основанный на курсоре
TYPE t1 IS VARRAY(50) OF c1%ROWTYPE;
TYPE t2 IS TABLE OF tbl1%ROWTYPE
- Индексированная таблица
INDEX BY BINARY_INTEGER;
- Объявление переменной
rec_t2 t2;
BEGIN
/* Использование переменной
типа "индексированная таблица" */
SELECT * INTO rec_t2(120) FROM tbl1
WHERE f1 = 120;
END;
Инициализация коллекций
Для инициализации коллекции используется конструктор - автоматически создаваемая
функция, одноименная с типом коллекции.
Конструктор создает коллекцию из значений переданного ему списка параметров.
Конструктор может быть вызван как в секции объявлений через знак присваивания после
указания типа, так и в теле программы. Вызов конструктора без параметров означает
инициализацию коллекции как пустой, но не устанавливает ее равной NULL.
Например:
DECLARE
CREATE TYPE rec_var1
AS VARRAY(3) OF num;
CREATE TYPE rec_var2
AS VARRAY(3) OF rec_obj;
r1 rec_var1; r2 rec_var2;
BEGIN
/* Инициализация коллекции
из трех элементов */
r1 := rec_var1 (2.0, 2.1, 2.2);
/*Инициализация varray-массива,
содержащего объекты типа rec_obj */
r2 := rec_var2 (rec_obj(1, 100, 'fff'),
rec_obj (2,110, 'ggg'),
rec_obj (3,120, 'jjj'));
Оператор CREATE TYPE позволяет сохранить определяемый тип в базе данных.
Конструктор можно вызывать в любом месте, где допустим вызов функции. Для того
чтобы добавить в таблицу базы данных строку, одно из полей которой имеет тип
коллекции, следует использовать конструктор.
Например:
BEGIN
INSERT INTO tbl_coll
VALUES (1, 'aaa', rec_obj
(3,120, 'jjj'));
Методы, применяемые при работе с коллекциями
В PL/SQL реализован ряд встроенных методов для работы с коллекциями. Эти методы
вызываются как
collection_name.method_name[(parameters)]
Эти методы нельзя вызывать из SQL-оператора.
В следующей таблице приведено описание встроенных функций, используемых для
работы с коллекциями.
Метод
Описание
EXISTS(n)
Если n-ый элемент коллекции существует, то функция возвращает значение TRUE
COUNT
Функция возвращает реальное количество элементов, которые содержит коллекция
LIMIT
Функция возвращает размер varray-массива или NULL - для вложенных таблиц
DELETE(m,n) Эта процедура удаляет элементы из вложенной или индексированной таблицы. Если
параметров не задано, то удаляются все элементы коллекции. При задании
параметра n удаляется n-ый элемент вложенной таблицы, а если задано оба
параметра, то удаляются все элементы в диапазоне от n до m
FIRST, LAST Функции возвращают наименьший и наибольший индекс элементов коллекции. Для
пустой вложенной таблицы обе функции возвращают значение NULL. Для Varrayмассивов вызов функции FIRST всегда возвращает значение 1
PRIOR(n)
Эта функция используется для цикла или последовательного просмотра элементов
вложенных таблиц и возвращает индекс элемента, предшествующего указанному
параметром n. Если такого элемента нет, то возвращается значение NULL
NEXT(n)
Функция употребляется для цикла или последовательного просмотра элементов
вложенных таблиц и возвращает индекс элемента, следующего за указанным
параметром n. Если такого элемента нет, то возвращается значение NULL
EXTEND(n,i) Функция увеличивает размер вложенной или индексированной таблицы, позволяя
добавлять в конец коллекции как один элемент, так и несколько элементов. Если
параметров не задано, то в коллекцию добавляется один null-элемент, а если указан
только параметр n, то добавляются n null-элементов. Если задано оба параметра, то
добавляются n элементов, являющихся копиями i-го элемента коллекции
TRIM(n)
Функция выполняет удаление одного или нескольких элементов вложенной или
индексированной таблицы. Если параметры не указаны, то удаляется один
последний элемент, а при задании параметра удаляются n последних элементов
коллекции. Если значение параметра превышает реальное количество элементов,
возвращаемое функцией COUNT, то инициируется исключение. Если элемент был
ранее удален функцией DELETE, то он все равно будет входить в число удаляемых
функцией TRIM элементов
Применение функций TRIM и EXTEND реализует для вложенных таблиц механизм стека,
позволяя удалять элементы и добавлять их в конец вложенной таблицы. Функция
DELETE выполняет удаление элементов, оставляя пустые места, которые впоследствии
учитываются функцией TRIM.
Значение, возвращаемое функцией COUNT, может использоваться как максимальное
значение для счетчика цикла по элементам коллекции.
Например:
FOR i IN 1..tbl1.COUNT LOOP
END LOOP;
Функция COUNT также позволяет определить количество строк, которые были извлечены
из столбца базы данных во вложенную таблицу.
Для Varray-массивов значение, возвращаемое функцией COUNT, эквивалентно значению,
возвращаемому функцией LAST. Для вложенных таблиц эти значения могут быть
различны в том случае, если выполнялась процедура DELETE, удаляющая элементы из
коллекции.
Перед тем как коллекция будет проинициализирована, можно использовать только метод
EXISTS. При вызове любого другого встроенного метода будет инициировано
исключение.
Например:
DECLARE
- Вложенная таблица
TYPE cl IS TABLE OF VARCHAR2(10);
c1 cl;
BEGIN
- Инициализации
- коллекции конструктором
c1 := cl('с 1', 'с 2', 'с 3');
- Удаление последнего (3-го) элемента
c1.DELETE(c1.LAST);
- Удаление двух последних элементов:
- (2-го и 3-го)
c1.TRIM(c1.COUNT);
- Запись в поток
- вывода значения 'с 1'
DBMS_OUTPUT.PUT_LINE(c1(1));
END;
Если при работе с коллекцией происходит ошибка, то Oracle инициирует бросок
исключения. В следующей таблице приведены основные причины возникновения ошибок
для коллекций.
Исключение
Причина ошибки
COLLECTION_IS_NULL
Коллекция не была инициализирована
NO_DATA_FOUND
Индекс ссылается на ранее удаленный элемент коллекции
SUBSCRIPT_BEYOND_COUNT Индекс больше, чем количество элементов в коллекции
SUBSCRIPT_OUTSIDE_LIMIT Индекс не принадлежит допустимому диапазону значений индекса
VALUE_ERROR
Значение индекса равно NULL или не может быть преобразовано в
целое
Исключительная ситуация не инициируется, если для процедуры DELETE в качестве
параметра передан индекс, равный NULL, а также при указании индекса ранее удаленного
элемента в случае его замещения.
Пакетный запрос многих строк
При запросе большого числа строк можно увеличить производительность, если вместо
поочерёдного зачитывания строк результата, зачитать их всех сразу, значительно снизив
тем самым количество переключений контекста от PL/SQL к SQL и обратно. Для
пакетного чтения необходимо снабдить оператор FETCH инструкцией BULK COLLECT.
Данные при этом должны записываться не в переменные, а в ассоциативные коллекции:
DECLARE
TYPE GenericCursor IS REF CURSOR;
c1 GenericCursor;
TYPE VarcharTable IS TABLE OF VARCHAR2(200) INDEX BY BINARY_INTEGER;
-- объявили тип данных "Таблица строк", элементы которой нумеруются
числами
empnames VarcharTable;
-- объявили переменную созданного типа
BEGIN
OPEN c1 FOR SELECT ename FROM employees;
FETCH c1 BULK COLLECT INTO empnames;
CLOSE c1;
END;
Выполнение операций DML
Операции DML, как правило, выполняются точно так же, как и в SQL:
DECLARE
BEGIN
UPDATE employees SET hire_date := SYSDATE WHERE id != 1;
INSERT INTO employees (name, city) VALUES ('SMITH', 'Тикси');
COMMIT;
END;
Динамический SQL
Динамические запросы
Для большей гибкости часто статические запросы заменяются запросами, формируемыми
динамически. Недостаток динамического SQL в том, что динамические запросы,
разумеется, не могут быть проверены на этапе компиляции. Если, например,
используемой в запросе таблицы не существует, то при работе выполнении операции OPEN
будет выброшено исключение.
Классическая задача, требующая применения динамического конструирования SQLзапросов, — отчёты в интерфейсах, где пользователь может выбрать разные условия, по
которым следует сформировать отчёт.
Ниже приведён анонимный блок кода, который в зависимости от некоего условия
запрашивает имя сотрудника либо по ключу, либо по городу.
DECLARE
TYPE GenericCursor IS REF CURSOR;
c1 GenericCursor;
sel VARCHAR2(4000);
bind_var VARCHAR2(200);
result VARCHAR2(200);
BEGIN
sel := 'SELECT name FROM employees WHERE 1 = 1';
IF ... THEN
sel := sel || ' AND id = :1';
bind_var := 12;
ELSE
sel := sel || ' AND city = :1';
bind_var := 'Магадан';
END IF;
OPEN c1 FOR sel USING bind_var;
FETCH c1 INTO result;
CLOSE c1;
END;
Динамические DML и DDL операции
Динамические операции DML и DDL выполняются с помощью оператора EXECUTE
IMMEDIATE.
DECLARE
BEGIN
EXECUTE IMMEDIATE 'DELETE FROM employees';
EXECUTE IMMEDIATE 'DROP TABLE employees';
-- COMMIT или ROLLBACK не нужен, потому что DDL-операция завершила
транзакцию
END;
Download