用户定义的函数只能有select语句

时间:2018-04-27 13:06:14

标签: sql oracle stored-procedures plsql user-defined-functions

UDF和SP之间的主要区别之一是UDF只能在其中包含select语句而不能插入/更新/删除语句。有人可以解释一下这背后的原因吗?以下功能:

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

无效。但为什么会这样呢?

2 个答案:

答案 0 :(得分:6)

您的函数中的insert语句缺少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

文档lists restrictions on functions called from SQLgoes into more detail in this warning

  

因为SQL是一种声明性语言,而不是命令式(或程序性)语言,所以你不知道SQL语句调用的函数会运行多少次 - 即使该函数是用PL / SQL编写的,这是一种命令式语言

如果允许该函数执行DML,那么您将无法控制执行DML的次数。例如,如果它正在执行插入操作,它可能会尝试将同一行插入两次并重复数据或获取约束违规。

答案 1 :(得分:2)

只是总结一下这些评论,可以在PL / SQL函数中包含DML。

你不能做的是从SQL调用该函数,因为select语句不应该同时应用更新和删除等作为隐藏的副作用。

首先,SQL语言保留以任何方式执行查询的权限,以任何顺序执行查询,以及它决定使用的任何缓存。 (它甚至可能在执行期间停止并重新启动。这取决于SQL引擎。)因此,您的函数可能会以任何顺序被调用一次或一百次,具体取决于执行计划,因此结果将是不可预测的。