Пользовательская функция может иметь только операторы select - PullRequest
0 голосов
/ 27 апреля 2018

Одно из основных различий между UDF и SP состоит в том, что UDF может иметь только операторы select внутри себя, но не операторы insert / update / delete. Может кто-нибудь объяснить, пожалуйста, причину этого? Функция ниже:

create function test(..)
...
BEGIN 
insert into EMPLOYEE('22',12000,'john');
return 0;
END

недействительно. Но почему это так?

Ответы [ 2 ]

0 голосов
/ 27 апреля 2018

В инструкции вставки внутри вашей функции отсутствует ключевое слово values;

insert into EMPLOYEE('22',12000,'john');

должно быть

insert into EMPLOYEE values ('22',12000,'john');

хотя лучше включить список имен столбцов. Из небольшой части кода, которую вы показали, это единственное, что является недействительным. Могут быть другие ошибки в пропущенных вами битах. (Если первый столбец в вашей таблице числовой, тогда вам не следует передавать строку - она ​​работает, но выполняет неявное преобразование и ее лучше избегать. А если столбец является строкой, должно ли это быть на самом деле?)

В UDF могут быть только операторы select, но не операторы вставки / обновления / удаления

Это не правильно. У вас может быть DML (вставка / обновление / удаление) в функции, но вы можете вызывать его только из контекста PL / SQL (хотя даже в PL / SQL часто говорят, что функции должны запрашивать данные без побочных эффектов и только процедур). следует изменить данные, но это не ограничено самим языком):

create table employee (id varchar2(3), salary number, name varchar2(10));

Table EMPLOYEE created.

create function test(unused number)
return number as
BEGIN 
  insert into EMPLOYEE (id, salary, name)
  values ('22',12000,'john');
  return 0;
END;
/

Function TEST compiled


declare
  rc number;
begin
  rc := test(42);
end;
/

PL/SQL procedure successfully completed.

select * from employee;

ID      SALARY NAME      
--- ---------- ----------
22       12000 john      

Но вы не можете вызвать его из контекста SQL:

select test(42) from dual;

ORA-14551: cannot perform a DML operation inside a query 
ORA-06512: at "MYSCHEMA.TEST", line 4

В документации перечислены ограничения на функции, вызываемые из SQL , и более подробно рассматривается в этом предупреждении :

Поскольку SQL является декларативным языком, а не императивным (или процедурным), вы не можете знать, сколько раз будет выполняться функция, вызываемая оператором SQL, даже если функция написана на PL / SQL, императивном языке .

Если бы функции было разрешено выполнять DML, то вы бы не контролировали, сколько раз выполнялся DML. Например, если он выполняет вставку, он может попытаться вставить одну и ту же строку дважды и либо дублировать данные, либо получить нарушение ограничения.

0 голосов
/ 27 апреля 2018

Просто, чтобы суммировать комментарии, вы можете иметь DML внутри функции PL / SQL.

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

С одной стороны, язык SQL оставляет за собой право выполнять запрос любым способом, который он выберет, в любом порядке и с любым кэшированием, которое он решит использовать. (Он может даже останавливаться и перезапускаться во время выполнения. Это зависит от механизма SQL.) Поэтому ваша функция может вызываться один или сто раз в любом порядке, в зависимости от плана выполнения, и поэтому результаты будут непредсказуемыми.

...