Встроенные методы коллекций PL/SQL

Встроенные методы коллекций PL/SQL

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 рекомендует использовать только один из этих двух методов при работе с конкретной коллекцией.

Вас заинтересует / Intresting for you:

Управление приложениями PL/SQL...
Управление приложениями PL/SQL... 4633 просмотров Stas Belkov Thu, 16 Jul 2020, 06:20:48
Символьные функции и аргументы...
Символьные функции и аргументы... 18545 просмотров Анатолий Wed, 23 May 2018, 18:54:01
Тип данных RAW в PL/SQL
Тип данных RAW в PL/SQL 12235 просмотров Doctor Thu, 12 Jul 2018, 08:41:33
Основы языка PL/SQL: ключевое ...
Основы языка PL/SQL: ключевое ... 12730 просмотров Дэн Fri, 05 Jan 2018, 03:13:29
Войдите чтобы комментировать

dbstalker аватар
dbstalker ответил в теме #9552 4 года 4 мес. назад
Отличное описание методов коллекций языка PL/SQL/ Добавляем в избранное)
AlexV аватар
AlexV ответил в теме #9175 5 года 6 мес. назад
Зер вери гуд статья! ЗачОтно!)