PL/SQL предоставляет для создаваемых вами коллекций множество встроенных функций и процедур, называемых методами коллекций. Эти методы предназначены для получения информации о содержимом коллекции и ее изменения. Их полный список приведен в табл. 1.
Метод (функция или процедура) | Описание |
COUNT (функция) | Возвращает текущее значение элементов в коллекции |
DELETE (процедура) | Удаляет из коллекции один или несколько элементов. Уменьшает значение, возвращаемое функцией COUNT, если заданные элементы еще не удалены. Со структурами VARRAY может использоваться только для удаления всего содержимого |
EXISTS (функция) | Возвращает значение TRUE или FALSE , определяющее, существует ли в коллекции заданный элемент |
EXTEND (процедура) | Увеличивает количество элементов во вложенной таблице или VARRAY , а также значение, возвращаемое функцией COUNT |
FIRST, LAST (функции) | Возвращают индексы первого (FIRST ) и последнего (LAST ) элемента в коллекции |
LIMIT (функция) | Возвращает максимальное количество элементов в массиве VARRAY |
PRIOR, NEXT (функции) | Возвращают индексы элементов, предшествующих заданному (PRIOR ) и следующему за ним (NEXT ). Всегда используйте PRIOR и NEXT для перебора коллекций, особенно при работе с разреженными (или потенциально разреженными) коллекциями |
TRIM (функция) | Удаляет элементы, начиная с конца коллекции (элемент с наибольшим индексом) |
Все эти конструкции называются методами, потому что синтаксис их вызова отличается от синтаксиса вызова обычных процедур и функций. Это типичный синтаксис вызова методов, используемый в объектно-ориентированных языках программирования — таких, как Java.
Рассмотрим синтаксис вызова методов на примере LAST
. Эта функция возвращает наибольший индекс элемента ассоциативного массива. Стандартный вызов этой функции выглядел бы так:
IF LAST (company_table) > 10 THEN ... /* Неверный синтаксис */
Иначе говоря, ассоциативный массив передается ей в качестве аргумента. Но поскольку функция LAST
является методом, она «принадлежит» объекту — в данном случае ассоциативному массиву. Правильный синтаксис ее вызова выглядит так:
IF company_table.LAST > 10 THEN ... /* Правильный синтаксис */
В общем случае синтаксис вызова методов ассоциативного массива выглядит так:
- Операция, не требующая передачи аргументов:
имя_таблицы.операция
- Операция, аргументами которой являются индексы элементов:
имя_таблицы.операция(индекс [, индекс])
Например, следующая команда возвращает TRUE
, если в ассоциативном массиве company_tab
определена запись 15:
company_tab.EXISTS(15)
Методы коллекций недоступны из SQL; их можно использовать только в программах PL/SQL.
Метод COUNT
Метод COUNT
возвращает количество элементов в ассоциативном массиве, вложенной таблице или массиве VARRAY
. В значении не учитываются элементы, удаленные из коллекции методом DELETE
или TRIM
.
Синтаксис вызова:
FUNCTION COUNT RETURN PLS_INTEGER;
Рассмотрим пример. Прежде чем что-либо делать с коллекцией, мы проверяем, содержит ли она хотя бы один элемент:
DECLARE
volunteer_list volunteer_list_ar := volunteer_list_ar('Steven');
BEGIN
IF volunteer_list.COUNT > 0
THEN
assign_tasks (volunteer_list);
END IF;
END;
Граничные условия
Для инициализированной коллекции, не содержащей ни одного элемента, COUNT
возвращает нуль. Это же значение возвращается при вызове COUNT
для пустого ассоциативного массива.
Возможные исключения
При вызове метода COUNT
для неинициализированной вложенной таблицы или VARRAY
инициируется заранее определенное исключение COLLECTION_IS_NULL
. Такое исключение не может возникнуть при работе с ассоциативными массивами, не требующими инициализации.
Метод DELETE
Метод DELETE
предназначен для удаления одного, нескольких или всех элементов ассоциативного массива, вложенной таблицы или массива VARRAY
. При вызове без аргументов он удаляет все элементы коллекции. Вызов DELETE
(i) удаляет i-й элемент вложенной таблицы или ассоциативного массива. А вызов DELETE
(i,j
) удаляет все элементы с индексами от i
до j
включительно. Если коллекция представляет собой ассоциативный массив, индексируемый строками, i
и j
должны быть строковыми значениями; в противном случае они являются целыми числами.
При вызове с аргументами метод резервирует место, занимавшееся «удаленным» элементом, и позднее этому элементу можно присвоить новое значение.
Фактически PL/SQL освобождает память лишь при условии, что программа удаляет количество элементов, достаточное для освобождения целой страницы памяти. (Если же метод DELETE
вызывается без параметров и очищает всю коллекцию, память освобождается немедленно.)
Применительно к массивам VARRAY
метод DELETE
может вызываться только без аргументов. Иначе говоря, с помощью указанного метода из этой структуры нельзя удалять отдельные элементы, поскольку в таком случае она станет разреженной, что недопустимо. Единственный способ удалить из VARRAY
один или несколько элементов — воспользоваться методом TRIM
, предназначенным для удаления группы расположенных рядом элементов, начиная с конца коллекции.
Следующая процедура удаляет из коллекции все элементы, кроме последнего. В ней используются четыре метода: FIRST
— для получения номера первого удаляемого элемента; LAST
— для получения номера последнего удаляемого элемента; PRIOR
— для определения номера предпоследнего элемента; DELETE
— для удаления всех элементов, кроме последнего:
PROCEDURE keep_last (the_list IN OUT List_t)
AS
first_elt PLS_INTEGER := the_list.FIRST;
next_to_last_elt PLS_INTEGER := the_list.PRIOR(the_list.LAST);
BEGIN
the_list.DELETE(first_elt, next_to_last_elt);
END;
Несколько дополнительных примеров:
- Удаление всех строк из таблицы
names
:
names.DELETE;
- Удаление 77-й строки из таблицы
globals
:
globals.DELETE (77);
- Удаление из таблицы
temp_reading
всех элементов, начиная с индекса –15 000 и до индекса 0 включительно:
temp_readings.DELETE (-15000, 0);
Граничные условия
Если значения индексов i
и/или j
указывают на несуществующие элементы, DELETE
пытается «сделать наилучшее» и не генерирует исключение. Например, если таблица содержит три элемента с индексами 1, 2 и 3, то вызов метода DELETE
(–5,1) удалит только один элемент с индексом 1, а вызов DELETE
(–5) не изменит состояния коллекции.
Возможные исключения
Вызов метода DELETE
для неинициализированной вложенной таблицы или массива VARRAY
инициирует исключение COLLECTION_
IS_NULL
.
Метод EXISTS
Метод EXISTS
используется с вложенными таблицами, ассоциативными массивами и массивами VARRAY
для определения наличия в коллекции заданного элемента. Если таковой имеется, метод возвращает значение TRUE
, а если отсутствует — значение FALSE
. Значение NULL
не возвращается ни при каких условиях. Кроме того, EXISTS
возвращает FALSE
и в том случае, если заданный элемент был удален из коллекции с помощью метода TRIM
или DELETE
.
Следующий блок проверяет, присутствует ли заданный элемент в коллекции, и при положительном ответе присваивает ему значение NULL
:
DECLARE
my_list color_tab_t := color_tab_t();
element PLS_INTEGER := 1;
BEGIN
...
IF my_list.EXISTS(element)
THEN
my_list(element) := NULL;
END IF;
END;
Граничные условия
Если метод EXISTS
вызывается для неинициализированной (содержащей атомарное значение NULL
) вложенной таблицы или структуры VARRAY
либо для инициализированной коллекции, не содержащей ни одного элемента, он просто возвращает значение FALSE
. Поэтому его можно вызывать без предварительной проверки вызовом COUNT
, не рискуя получить сообщение об ошибке.
Возможные исключения
Метод EXISTS
не инициирует исключения.
Метод EXTEND
Чтобы добавить элемент во вложенную таблицу или массив VARRAY
, необходимо сначала выделить для него область памяти. Соответствующая операция, не зависящая от присваивания элементу значения, выполняется методом EXTEND
. Следует помнить, что указанный метод неприменим к ассоциативным массивам.
Метод EXTEND
, как уже было сказано, добавляет элементы в коллекцию. При вызове без аргументов он добавляет один элемент со значением NULL
. Вызов EXTEND
(n
) присоединяет n элементов со значением NULL
, а вызов EXTEND
(n,i
) — n
элементов, и всем им присваивает значение i
-го элемента. Последняя форма метода применяется к коллекциям, для элементов которых задано ограничение NOT NULL
.
Синтаксис перегруженного метода EXTEND
:
PROCEDURE EXTEND (n PLS_INTEGER:=1);
PROCEDURE EXTEND (n PLS_INTEGER, i PLS_INTEGER);
В следующем примере процедура push
добавляет в список один элемент и присваивает ему новое значение:
PROCEDURE push (the_list IN OUT List_t, new_value IN VARCHAR2)
AS
BEGIN
the_list.EXTEND;
the_list(the_list.LAST) := new_value;
END;
В другом фрагменте кода метод EXTEND
используется для включения в коллекцию 10 новых элементов с одинаковыми значениями. Сначала в коллекцию добавляется один элемент, которому явно присваивается нужное значение. При повторном вызове метода EXTEND
в коллекцию добавляется еще 9 элементов, которым присваивается значение первого элемента коллекции new_value
:
PROCEDURE push_ten (the_list IN OUT List_t, new_value IN VARCHAR2)
AS
l_copyfrom PLS_INTEGER;
BEGIN
the_list.EXTEND;
l_copyfrom := the_list.LAST;
the_list(l_copyfrom) := new_value;
the_list.EXTEND (9, l_copyfrom);
END;
Граничные условия
Если параметр n
имеет значение NULL
, метод не выполнит никаких действий.
Возможные исключения
При вызове метода EXTEND
для неинициализированной вложенной таблицы или VARRAY
инициируется исключение COLLECTION_IS_NULL
. Попытка добавить в массив VARRAY
элементы, индекс которых превышает максимальный индекс массива в его объявлении, инициирует исключение SUBSCRIPT_BEYOND_LIMIT
.
Методы FIRST и LAST
Методы FIRST
и LAST
возвращают соответственно наименьший и наибольший индексы элементов вложенной таблицы, ассоциативного массива или массива VARRAY
. Для ассоциативных массивов, индексируемых строками, эти методы возвращают строки; «наименьшее» и «наибольшее» значения определяются порядком набора символов, используемого данным сеансом. Для других типов коллекций методы возвращают целые числа.
Синтаксис этих функций:
FUNCTION FIRST RETURN PLS_INTEGER | VARCHAR2;
FUNCTION LAST RETURN PLS_INTEGER | VARCHAR2;
Так, следующий фрагмент перебирает все элементы коллекции от начала к концу:
FOR indx IN holidays.FIRST .. holidays.LAST
LOOP
send_everyone_home (indx);
END LOOP;
Запомните, что такой цикл будет выполнен корректно (то есть не породит исключения NO_DATA_FOUND
) лишь при условии, что коллекция является плотной.
В следующем примере для добавления элементов в конец ассоциативного массива используется оператор COUNT
. Цикл FOR
с курсором используется для копирования данных из базы в ассоциативный массив. При выборке первой записи коллекция companies
пуста, поэтому COUNT
возвращает 0.
FOR company_rec IN company_cur
LOOP
companies ((companies.COUNT) + 1).company_id
company_rec.company_id;
END LOOP;
Граничные условия
Если методы FIRST
и LAST
вызываются для инициализированных коллекций, не содержащих ни одного элемента, они возвращают NULL
. Для массива VARRAY
, всегда содержащего хотя бы один элемент, FIRST
всегда возвращает 1, а LAST
— то же значение, что и метод COUNT
.
Возможные исключения
При вызове методов FIRST
и LAST
для неинициализированной вложенной таблицы или массива VARRAY
инициируется исключение COLLECTION_ IS_NULL.
Метод LIMIT
Метод LIMIT
возвращает максимальное количество элементов, которое можно определить в массиве VARRAY
. В случае вложенной таблицы или ассоциативного массива он возвращает NULL
. Синтаксис этого метода:
FUNCTION LIMIT RETURN PLS_INTEGER;
В следующем примере перед добавлением нового элемента в конец массива VARRAY
мы сначала проверяем, есть ли в нем еще свободное место:
IF my_list.LAST < my_list.LIMIT
THEN
my_list.EXTEND;
END IF;
Граничные условия
У метода LIMIT
граничных условий не существует.
Возможные исключения
Вызов метода LIMIT
для неинициализированной вложенной таблицы или массива VARRAY
генерирует исключение COLLECTION_ IS_NULL
.
Методы PRIOR и NEXT
Методы PRIOR
и NEXT
используются для перемещения по коллекциям — вложенным таблицам, ассоциативным массивам и массивам VARRAY
. Метод PRIOR
возвращает индекс предыдущего, а метод NEXT
— следующего элемента коллекции. Следующая функция возвращает сумму чисел, хранящихся в коллекции list_t
:
FUNCTION compute_sum (the_list IN list_t) RETURN NUMBER
AS
row_index PLS_INTEGER := the_list.FIRST;
total NUMBER := 0;
BEGIN
LOOP
EXIT WHEN row_index IS NULL;
total := total + the_list(row_index);
row_index := the_list.NEXT(row_index);
END LOOP;
RETURN total;
END compute_sum;
Та же программа, но с перебором элементов от последней к первой определенной записи коллекции:
FUNCTION compute_sum (the_list IN list_t) RETURN NUMBER
AS
row_index PLS_INTEGER := the_list.LAST;
total NUMBER := 0;BEGIN
LOOP
EXIT WHEN row_index IS NULL;
total := total + the_list(row_index);
row_index := the_list.PRIOR(row_index);
END LOOP;
RETURN total;
END compute_sum;
В данном случае направление перемещения не имеет значения, но в других программах оно может повлиять на результат обработки.
Граничные условия
Методы PRIOR
и NEXT
для инициализированной коллекции, не содержащей ни одного элемента, возвращают NULL
. Если значение i больше или равно COUNT
, метод NEXT
возвращает NULL
; если i меньше или равно FIRST
, метод PRIOR
возвращает NULL
.
Вплоть до версии Oracle12c, если коллекция не пуста, а параметр i больше или равен COUNT
, метод PRIOR
возвращает LAST
; если параметр i меньше FIRST
, метод NEXT
возвращает FIRST
. Однако сохранение такого поведения в будущих версиях Oracle не гарантировано.
Возможные исключения
Вызов методов PRIOR
и NEXT
для неинициализированной вложенной таблицы или массива VARRAY
генерирует исключение COLLECTION_IS_NULL
.
Метод TRIM
Метод TRIM
удаляет n последних элементов коллекции — вложенной таблицы или массива VARRAY
. Если метод вызывается без аргументов, он удалит только один элемент. Как упоминалось ранее, при совместном использовании методов TRIM
и DELETE
возможна накладка: если заданный в вызове метода TRIM
элемент был уже удален методом DELETE
, метод TRIM
«повторит» удаление, но считает его частью n, поэтому количество реально удаленных элементов окажется меньшим, чем вы рассчитывали.
Попытка вызова метода TRIM
для ассоциативного массива приведет к ошибке компиляции.
Синтаксис метода TRIM
:
PROCEDURE TRIM (n PLS_INTEGER:=1);
Следующая функция извлекает из списка последнее значение и возвращает его вызывающему блоку. Операция извлечения реализуется как выборка значения с последующим усечением коллекции на один элемент:
FUNCTION pop (the_list IN OUT list_t) RETURN VARCHAR2
AS
l_value VARCHAR2(30);
BEGIN
IF the_list.COUNT >= 1
THEN
/* Сохраняем значение последнего элемента коллекции,
|| которое будет возвращено функцией
*/
l_value := the_list(the_list.LAST);
the_list.TRIM;
END IF;
RETURN l_value;
END;
Граничные условия
Если значение n
равно NULL
, метод не выполнит никаких действий.
Возможные исключения
При попытке удалить больше элементов, чем имеется в коллекции, инициируется исключение SUBSCRIPT_BEYOND_COUNT
. Если метод TRIM
вызывается для неинициализированной вложенной таблицы или массива VARRAY
, инициируется исключение COLLECTION_IS_NULL
.
Вызывая методы TRIM
и DELETE
для одной и той же коллекции, можно получить неожиданные результаты. На сколько элементов станет меньше в коллекции, если удалить последний элемент методом DELETE
, а затем вызвать метод TRIM
с тем же значением параметра? Казалось бы, это приведет к удалению двух элементов, но в действительности оба метода удалят один и тот же элемент. Чтобы избежать накладок, компания Oracle рекомендует использовать только один из этих двух методов при работе с конкретной коллекцией.