【问题标题】:User defined function can only have select statements用户定义的函数只能有选择语句
【发布时间】:2018-04-27 13:06:13
【问题描述】:

UDF 和 SP 之间的主要区别之一是 UDF 中只能包含 select 语句,而不能包含 insert/update/delete 语句。有人可以解释一下这背后的原因吗?下面的功能:

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

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

【问题讨论】:

  • 一个函数返回可以在SELECT语句中使用的值。这两种结构做不同的事情。
  • @GordonLinoff 我说的是功能块内的选择语句。我已经编辑了我的问题。
  • 函数可以做插入/更新/删除;如果他们这样做,您就不能从 SQL 上下文中调用它们,只能从 PL/SQL 中调用它们。 (而且这通常被认为是不好的做法。)为什么你认为你展示的内容是无效的?
  • @AlexPoole 我认为由于函数需要返回一些值并插入等实际上只返回更新的行数,所以将它们放在函数中没有意义吗?
  • @AlexPoole 你问我“为什么你认为你展示的内容是无效的”,这就是我的想法..

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


【解决方案1】:

函数内的插入语句缺少values 关键字;

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

应该是

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

虽然最好也包含列名列表。从您展示的代码的一小部分来看,这是唯一无效的。您省略的位中可能还有其他错误。 (如果表中的第一列是数字,那么您不应该传递字符串 - 它可以工作,但会进行隐式转换,最好避免。如果该列是字符串,是否真的应该如此?)

UDF 里面只能有 select 语句,不能有 insert/update/delete 语句

这是不正确的。您可以在函数中使用 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 的次数。例如,如果它正在执行插入操作,它可能会尝试两次插入同一行并重复数据或违反约束。

【讨论】:

    【解决方案2】:

    总结一下 cmets,您可以在 PL/SQL 函数中使用 DML。

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

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

    【讨论】:

    • 您可以在从 SQL 调用的 PL/SQL 函数中包含非查询 DML - 它只需要是一个自治事务。 :-) 我不建议这样做 - 存在各种潜在问题,但有可能。
    猜你喜欢
    • 1970-01-01
    • 2011-01-26
    • 2022-10-12
    • 2010-09-26
    • 2012-01-07
    • 2010-12-13
    • 1970-01-01
    • 1970-01-01
    • 2020-10-13
    相关资源
    最近更新 更多