Oracle функция не может быть использована в sql

Обновлено: 04.07.2024

Думаю, многие из вас помнят или, по крайней мере, работали с такой конструкцией:

  1. Любая функция, вызываемая из SQL-оператора, не может модифицировать таблицы базы данных (WNDS).
  2. Для того, чтобы функция могла быть выполнена удаленно (через связь базы данных) или параллельно, она не должна читать или записывать значения модульных переменных (RNPS или WNPS).
  3. Функция, вызываемая из команды SELECT, VALUES или SET, могут записывать модульные переменные. Во всех других командах, функции должны иметь уровень строгости WNPS.
  4. Функция строга настолько, насколько строги вызываемые ею подпрограммы. Если функция вызывает хранимую процедуру, которая выполняет к примеру обновление информации (оператор UPDATE), то функция не имеет уровня строгости WNDS и следовательно не может быть использована в SQL-операторе.
  5. Независимо от уровня строгости, хранимые функции PL/SQL - нельзя использовать в ограничении CHECK команды CREATE TABLE или ALTER TABLE. А так же использовать для указания значения по умолчанию, для столбца, так как в этих ситуациях требуется, чтобы описания не изменялись.

То есть, если сказать более просто, не применяйте вызовы тех функций, которые модифицируют таблицы! Давайте опишем уровни строгости функций вот такой табличкой:

  1. Функция должна храниться в БД или отдельно или быть частью модуля. Она не должна быть локальной по отношению к другому блоку.
  2. Функция должна иметь входные параметры только с типом IN! Но не IN OUT или OUT!
  3. Для формальных параметров должны использоваться только те типы, которые применяются в БД, но не типы PL/SQL, такие как BOOLEAN или RECORD! Типы БД это - NUMBER, CHAR, VARCHAR2, ROWID, LONG, LONG ROW и DATE.
  4. Тип возвращаемый функцией так же должен быть типом БД!

Рассмотрим пример для всего вышеизложенного. Напишем простую функцию, которая по ключевому полю конкатенирует строки из таблицы SALESREPS. А затем выполним SQL-оператор, применив нашу функцию.

Получаем после компиляции:

А теперь SQL - оператор:

Как видите наш SQL- оператор сработал без замечаний! Так как все, что мы делали соответствует purity level! А вот для модульных функций дело обстоит несколько иначе. Для того, чтобы в модулях определять уровни строгости необходима прагма - RESTRICT_REFERENCES (ограничить ссылки). Эта прагма устанавливает уровень строгости для конкретной функции. Записывается она следующим образом:

Например заголовок нашего модуля из шага 97 мог быть записан вот так:

Здесь мы применили ее дважды, так как задали прагму для двух функций. В чем собственно необходимость использования прагмы RESTRICT_REFERENCES? Почему прагма применяется в модульной функции и не обязательна для автономной? Ответить на этот вопрос можно проанализировав взаимосвязи, между заголовком и телом модуля. Вспомним, что блоки PL/SQL вызывающие модульную функцию зависят только от заголовка модуля, но не от его тела. Более того при создании вызывающего блока тело модуля вообще может отсутствовать. Поэтому компилятору PL/SQL необходимо указание помогающее определить уровни строгости модульной функции, чтобы проверить корректность использования функции в вызывающем блоке. При последующих модификациях, тела модуля код функции проверяется на соответствие заданной прагме. Те же правила справедливы и для переопределенных функций. Модули, которые встроены в сам PL/SQL не являются строгими. По этому не могут быть включены в SQL - оператор! Например DBMS_OUTPUT. И на последок, при вызове функций в SQL - операторах, формальные параметры могут иметь значение по умолчанию. Но применять позиционное представление запрещается! Вот собственно, этот раздел и замыкает тематику работы с пакетами.

Табличные функции SQL и PL/SQL

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

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

Табличные функции открывают массу полезных возможностей для разработчиков PL/SQL . Чтобы продемонстрировать некоторые из этих возможностей, мы поближе познакомимся с потоковыми и конвейерными табличными функциями.

Потоковые табличные функции

Потоковая передача данных позволяет переходить между процессами или стадиями без использования вспомогательных структур данных. Табличные функции в сочетании с выражением CURSOR позволяют организовать потоковую передачу данных через не­сколько промежуточных преобразований в одной команде SQL .

Конвейерные табличные функции

Эти функции возвращают результирующий набор в конвейерном режиме, то есть данные поступают, пока функция продолжает выполняться. Добавьте секцию PARALLEL_ENABLE в заголовок конвейерной функции — и у вас появляется функция, которая будет вы­полняться параллельно в параллельном запросе.

До выхода Oracle Database 12c табличные функции могли возвращать только вложенные таблицы и VARRAY . Начиная с версии 12.1 появилась возможность определения табличных функций, возвращающих ассоциативные массивы с цело­численными индексами, тип которых определяется в спецификации пакета.

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

Вызов функции из секции FROM

Чтобы вызвать функцию из секции FROM , необходимо сделать следующее:

  • Определить тип данных RETURN функции как тип коллекции (вложенная таблица или VARRAY ).
  • Убедиться в том, что все остальные параметры функции имеют режим IN и тип дан­ных SQL . (Например, из запроса не удастся вызвать функцию, аргумент которой относится к логическому типу или типу записи.)
  • Встроить вызов функции в оператор TABLE (в Oracle8i придется использовать опе­ратор cast).

Рассмотрим простой пример использования табличной функции. Мы начнем с создания типа вложенной таблицы на базе объектного типа pets :

Затем создается функция с именем pet_family . В ее аргументах передаются два объекта pet . Далее в зависимости от значения breed возвращается вложенная таблица с инфор­мацией обо всем семействе, определенной в коллекции:

Функция pet_family тривиальна; здесь важно понять, что функция PL/SQL может содержать сколь угодно сложную логику, которая реализуется средствами PL/SQL и выходит за рамки выразительных возможностей SQL .

Теперь эта функция может вызываться в секции FROM запроса :

Часть выходных данных:

Передача результатов вызова табличной функции в курсорной переменной

Табличные функции помогают решить проблему, с которой разработчики сталкивались в прошлом, — а именно как передать данные, полученные в программе PL/SQL (то есть данные, не хранящиеся в таблицах базы данных), в управляющую среду без поддержки PL/SQL ? Курсорные переменные позволяют легко передать результирующие наборы на базе SQL , допустим, в программу Java, потому что курсорные переменные поддер­живаются в JDBC . Но если сначала нужно провести сложные преобразования в PL/ SQL , как вернуть эти данные вызывающей программе?

Теперь эта проблема решается объединением мощи и гибкости табличных функций с ши­рокой поддержкой курсорных переменных в средах без поддержки PL/SQL . Допустим, я хочу сгенеририровать данные семейства животных (полученные вызовом функции pet_family из предыдущего раздела) и передать строки данных интерфейсному приложению, написанному на Java.

Это делается очень просто:

В этой программе я воспользуюсь преимуществами предопределенного слабого курсор­ного типа SYS_REFCURSOR (появившегося в Oracle9i Database ) для объявления курсорной переменной. Курсорная переменная открывается вызовом OPEN FOR и связывается с за­просом, построенным на базе табличной функции pet_family .

Затем курсорная переменная передается интерфейсной части Java . Так как JDBC распознает курсорные переменные, код Java легко выполняет выборку строк данных и интегрирует их в приложение.

Создание потоковой функции

Потоковая функция получает параметр с результирующим набором (через выражение CURSOR ) и возвращает результат в форме коллекции. Так как к коллекции можно при­менить оператор TABLE , а затем запросить данные командой SELECT , эти функции по­зволяют выполнить одно или несколько преобразований данных в одной команде SQL . Потоковые функции, поддержка которых добавилась в Oracle9i Database , позволяют скрыть алгоритмическую сложность за интерфейсом функции, и упростить SQL прило­жения. Приведенный ниже пример объясняет различные действия, которые необходимо выполнить для такого использования табличных функций.

Представьте следующую ситуацию: имеется таблица с информацией биржевых коти­ровок, которая содержит строки с ценами на моменты открытия и закрытия биржи:

Эту информацию необходимо преобразовать в другую таблицу:

Иначе говоря, одна строка stocktable превращается в две строки tickertable . Эту задачу можно решить многими способами. Самое элементарное и традиционное решение на PL/SQL выглядит примерно так:

Также возможны решения, полностью основанные на SQL :

А теперь предположим, что для перемещения данных из stocktable в tickertable требуется выполнить очень сложное преобразование, требующее использования PL/ SQL . В такой ситуации табличная функция, используемая для передачи преобразуемых данных, потребует намного более эффективного решения.

Прежде всего, при использовании табличной функции нужно будет возвращать вложен­ную таблицу или массив VARRAY с данными. Я выбрал вложенную таблицу, потому что для VARRAY нужно задать максимальный размер, а я не хочу устанавливать это ограни­чение в своей реализации. Тип вложенной таблицы должен быть определен как тип на уровне схемы или в спецификации пакета, чтобы ядро SQL могло разрешить ссылку на коллекцию этого типа. Конечно, хотелось бы вернуть вложенную таблицу, основанную на самом определении таблицы, — то есть чтобы определение выглядело примерно так:

К сожалению, эта команда завершится неудачей, потому что %ROWTYPE не относится к числу типов, распознаваемых SQL. Этот атрибут доступен только в разделе объявле­ний PL/SQL . Следовательно, вместо этого придется создать объектный тип, который воспроизводит структуру реляционной таблицы, а затем определить тип вложенной таблицы на базе этого объектного типа:

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

Я создал пакет для типа REF CURSOR , основанного на новом типе вложенной таблицы:

Работа завершается написанием функции преобразования:

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

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

Внутренняя команда SELECT извлекает все строки таблицы stocktable . Выражение CURSOR , в которое заключен запрос, преобразует итоговый набор в курсорную переменную, которая передается stockpivot. Функция возвращает вложенную таблицу, а оператор TABLE преобразует ее к формату реляционной таблицы, к которой можно обращаться с запросами.

Никакого волшебства, и все же выглядит немного волшебно, правда? Но вас ждет нечто еще более интересное — конвейерные функции!

Создание конвейерной функции

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

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

Строки Описание
2 По сравнению с исходной версией stockpivot добавлено ключевое слово PIPELINED
4-5 Объявление локального объекта и локальной записи, как и в первой версии. В этих
строках интересно то, что не объявляется, — а именно вложенная таблица, которая будет возвращаться функцией. Намек на то, что будет дальше…
7-9 Начало простого цикла с выборкой каждой строки из курсорной переменной; цикл завершается, когда в курсоре не остается данных
12-15 и 19-21 Заполнение локального объекта для строк tickertable (на моменты открытия и закрытия)
16-21 Команда PIPE ROW (допустимая только в конвейерных функциях) немедленно передает
объект, подготовленный функцией
25 В конце исполняемого раздела функция ничего не возвращает! Вместо этого она вызывает RETURN без указания значения (что прежде разрешалось только в процедурах) для возврата управления вызывающему блоку. Функция уже вернула все свои данные командами PIPE ROW

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

Мои тесты показывают, что в Oracle Database 10g и Oracle Database 11g при преобра­зовании 100 000 строк в 200 000 и последующем возвращении только первых 9 строк конвейерная версия завершает свою работу за 0,2 секунды, тогда как выполнение не­конвейерной версии занимает 4,6 секунды.

Как видите, конвейерная передача строк работает, и обеспечивает существенный выигрыш!

Активизация параллельного выполнения функции

Одним из огромных достижений PL/SQL , появившихся в Oracle9i Database, стала воз­можность выполнения функций в контексте параллельных запросов. До выхода Oracle9i Database вызов функции PL/SQL в SQL переводил запрос в режим последовательного выполнения — существенная проблема для хранилищ данных большого объема. Теперь в заголовок конвейерной функции можно добавить информацию, которая подскажет исполнительному ядру, каким образом передаваемый функции набор данных следует разбить для параллельного выполнения.

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

  • Функция может выполняться параллельно, а данные, передаваемые этой функции, могут разбиваться произвольно:

В этом примере ключевое слово ANY выражает утверждение программиста о том, что результаты не зависят от порядка получения входных строк функцией. При ис­пользовании этого ключевого слова исполнительная система случайным образом разбивает данные между процессами запроса. Это ключевое слово подходит для функций, которые получают одну строку, работают с ее столбцами, а затем генери­руют выходные строки по содержимому столбцов только этой строки. Если в вашей программе действуют другие зависимости, результат становится непредсказуемым.

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

Oracle называет такой способ группировки записей кластерным; столбец, по которому осуществляется группировка (в данном случае department ), называется кластерным ключом. Здесь важно то, что для алгоритма несущественно, в каком порядке значений кластерного ключа он будет получать кластеры, и Oracle не гарантирует никакого конкретного порядка получения. Тем самым обеспечивается ускорение работы алгоритма по сравнению с кластеризацией и передачей строк в порядке значений кластерного ключа. Алгоритм выполняется со сложностью N вместо N log(N) , где N — количество записей.

В данном примере в зависимости от имеющейся информации о распределении зна­чений можно выбрать между HASH (department) и RANGE (department). HASH работает быстрее, и является более естественным вариантом для использования с CLUSTER.. .BY .

  • Функция должна выполняться параллельно, а строки, передаваемые конкретному процессу в соответствии с PARTITION. BY (для этого раздела), будут проходить ло­кальную сортировку этим процессом.

Фактически происходит параллелизация сортировки, поэтому команда SELECT , ис­пользуемая для вызова табличной функции, не должна содержать секции ORDER. BY (так как ее присутствие будет противоречить попытке параллелизации сортировки). Следовательно, в данном случае естественно использовать вариант RANGE в сочетании с ORDER. ..BY . Реализация будет работать медленнее, чем CLUSTER. BY , поэтому этот вариант следует использовать только в том случае, если алгоритм зависит от него.

Конструкция CLUSTER. BY не должна использоваться вместе с ORDER. BY в объявлении табличной функции. Это означает, что алгоритм, зависящий от кластеризации по одному ключу cl с последующим упорядочением набора запи­сей с заданным значением cl, скажем, по c2, должен проходить параллелизацию с использованием ORDER. BY в объявлении табличной функции.

что то типа того и вызываю

Вместо этого:
"--вот здесь уже можешь пользоваться результатом функции"
делаю к примеру:

select n from dual

select n from dual

пишет: В этом предложении SELECT ожидается фраза INTO

1) Во-первых, сходите-ка изучите то, как возвращать результаты SELECT в код PL/SQL. (вообще,
ей-богу, тут элементарный здравый смысл уже должен работать)

2) Во-вторых, сходите-ка изучите то, какие функции могут использоваться в выражениях SQL,
в частности, могут ли там присутствовать OUT-параметры

select n from dual

пишет: В этом предложении SELECT ожидается фраза INTO

1) Во-первых, сходите-ка изучите то, как возвращать результаты SELECT в код PL/SQL. (вообще,
ей-богу, тут элементарный здравый смысл уже должен работать)

2) Во-вторых, сходите-ка изучите то, какие функции могут использоваться в выражениях SQL,
в частности, могут ли там присутствовать OUT-параметры

3) В-третьих, изучите способы вызова функций в PL/SQL.

Вместо этого:
"--вот здесь уже можешь пользоваться результатом функции"
делаю к примеру:

select n from dual

пишет: В этом предложении SELECT ожидается фраза INTO

Что бы Вы хотели видеть в результате?

Функция
overdlib.Return_Rest_ACR(itcracc, 'RUR', to_date('311208','DDMMYY')) Rest455
будет в этом селекте возвращать остаток в поле Rest455.
Как то вот так же можно функцию указаную выше прикрутить с этими IN OUT. Никогда с ними не сталкивался.

Функция
overdlib.Return_Rest_ACR(itcracc, 'RUR', to_date('311208','DDMMYY')) Rest455
будет в этом селекте возвращать остаток в поле Rest455.
Как то вот так же можно функцию указаную выше прикрутить с этими IN OUT. Никогда с ними не сталкивался.

Куда Вы хотите в запросе OUT параметры вывести? Или они НЕ НУЖНЫ Вам как OUT?

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

Пользовательские функции в SQL и PL/SQL

Oracle позволяет вызывать пользовательские функции в коде SQL . Фактически это позволяет адаптировать язык SQL под требования конкретных приложений.

Каждый раз, когда исполнительное ядро SQL вызывает функцию PL/SQL, оно должно «переключаться» на исполнительное ядро PL/SQL. При многократном вызове функции затраты на переключение контекстов могут быть весьма значи­тельными.

Требования к вызываемым функциям

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

  • Все параметры функции должны иметь режим использования IN . Режимы IN OUT и OUT в функциях, встраиваемых в SQL-код, недопустимы.
  • Типы данных параметров функций и тип возвращаемого значения должны распоз­наваться сервером Oracle. PL/SQL дополняет основные типы Oracle, которые пока не поддерживаются базой данных. Речь идет о типах BOOLEAN , BINARY_INTEGER , ассо­циативных массивах, записях PL/SQL и определяемых программистом подтипах.
  • Функция должна храниться в базе данных. Функция, определенная на стороне клиента, не может вызываться в командах SQL, так как SQL не сможет разрешить ссылку на эту функцию.

По умолчанию пользовательские функции, вызываемые в SQL , оперируют данными одной строки, а не столбца (как агрегатные функции SUM , MIN и AVG ). Чтобы соз­дать агрегатные функции, вызываемые в SQL , необходимо использовать интерфейс ODCIAggregate , который является частью среды Oracle Extensibility Framework . За подробной информацией по этой теме обращайтесь к документации Oracle.

Ограничения для пользовательских функций, вызываемых в SQL

С целью защиты от побочных эффектов и непредсказуемого поведения хранимых про­цедур Oracle не позволяет им выполнять следующие действия:

  • Хранимые функции не могут модифицировать таблицы баз данных и выполнять команды DDL ( CREATE TABLE , DROP INDEX и т. д.), INSERT , DELETE , MERGE и UPDATE . Эти ограничения ослабляются, если функция определена как автономная транзакция. В таком случае любые вносимые ею изменения осуществляются не­зависимо от внешней транзакции, в которой выполняется запрос.
  • Хранимые функции, которые вызываются удаленно или в параллельном режиме, не могут читать или изменять значения переменных пакета. Сервер Oracle не поддер­живает побочные эффекты, действие которых выходит за рамки сеанса пользователя.
  • Хранимая функция может изменять значения переменных пакета, только если она вызывается в списке выборки либо в предложении VALUES или SET . Если хранимая функция вызывается в предложении WHERE или GROUP BY , она не может изменять значения переменных пакета.
  • До выхода Oracle8 пользовательские функции не могли вызывать процедуру RAISE_ APPLICATION_ERROR .
  • Хранимая функция не может вызывать другой модуль (хранимую процедуру или функцию), не соответствующий приведенным требованиям.
  • Хранимая функция не может обращаться к представлению, которое нарушает любое из предшествующих правил. Представлением (view) называется хранимая команда SELECT , в которой могут вызываться хранимые функции.
  • До выхода Oracle11g для передачи параметров функциям могла использоваться только позиционная запись. Начиная с Oracle11g, допускается передача параметров по имени и смешанная запись.

Непротиворечивость чтения и пользовательские функции

Модель непротиворечивости чтения в базе данных Oracle проста и понятна: после выполнения запрос «видит» данные в том состоянии, в котором они существовали (были зафиксированы в базе данных) на момент начала запроса, с учетом результатов изменений, вносимых командами DML текущей транзакции. Таким образом, если мой запрос был выполнен в 9:00 и продолжает работать в течение часа, даже если за это время другой пользователь внесет в данные изменения, они не отразятся в моем запросе.

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

Таблица account содержит 5 миллионов активных строк, а таблица orders — 20 миллио­нов. Я запускаю запрос в 10:00, на его завершение уходит около часа. В 10:45 приходит некто, обладающий необходимыми привилегиями, удаляет все строки из таблицы orders и закрепляет транзакцию. По правилам модели непротиворечивости чтения Oracle сеанс, в котором выполняется запрос, не должен рассматривать эти строки как удаленные до завершения запроса. Но при следующем вызове из запроса функция total_sales не найдет ни одной строки и вернет NULL — и так будет происходить до завершения запроса.

При выполнении запросов из функций, вызываемых в коде SQL, необходимо внимательно следить за непротиворечивостью чтения. Если эти функции вызываются в продолжитель­ных запросах или транзакциях, вероятно, вам стоит выполнить следующую команду для обеспечения непротиворечивости чтения между командами SQL текущей транзакции: SET TRANSACTION READ ONLY

В этом случае необходимо позаботиться о наличии достаточного табличного простран­ства отмены.

Определение подпрограмм PL/SQL в командах SQL (12.1 и выше)

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

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

Эта возможность позволяет «расширить» язык SQL функциональностью, присущей конкретному приложению, и повторно использовать алгоритмы (вместо копирования). К недостаткам выполнения пользовательских функций в SQL следует отнести необ­ходимость переключения контекста между исполнительными ядрами SQL и P L/SQL . Начиная с Oracle Database 12c вы можете определять функции и процедуры PL/SQL в секции WITH подзапроса, чтобы затем использовать их как любую встроенную или пользовательскую функцию. Эта возможность позволяет консолидировать функцию и запрос в одной команде:

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

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

Классическое обходное решение основано на определении функции в пакете и ее по­следующем вызове:

Для простого обращения к значению константы в команде SQL потребуется слишком много кода и усилий. Начиная с версии 12.1 это стало излишним — достаточно создать функцию в секции WITH :

Функции PL/SQL , определяемые в SQL, также пригодятся при работе с автономными базами данных, доступными только для чтения. Хотя в таких базах данных невозмож­но создавать «вспомогательные» функции PL/SQL , вы можете определять их прямо в запросах.

Механизм WITH FUNCTION стал чрезвычайно полезным усовершенствованием языка SQL. Тем не менее каждый раз, когда вы планируете его использование, стоит задать себе один вопрос: «Потребуется ли эта функциональность в нескольких местах приложения?»

Если вы ответите на него положительно, следует решить, компенсирует ли выигрыш по производительности от применения WITH FUNCTION потенциальные потери от копи­рования и вставки этой логики в нескольких командах SQL.

Учтите, что в версии 12.1 в блоках PL/SQL невозможно выполнить статическую коман­ду select с секцией with function . Безусловно, это выглядит очень странно, и я уверен, что в 12.2 такая возможность появится, но пока при попытке выполнения следующего кода будет выдана ошибка:

Помимо конструкции WITH FUNCTION, в версии 12.1 также появилась директива UDF для улучшения быстродействия функций PL/SQL, выполняемых из SQL.

Читайте также: