在SELECT语句中调用Oracle存储过程

17

我正在处理一个查询(SELECT),并且需要将其结果插入到一个表格中。 在进行插入之前,我需要进行一些检查,如果所有列都有效,则进行插入。

检查是在存储过程中完成的。同样的存储过程也在其他地方使用。 因此,我考虑使用相同的存储过程来进行检查。

存储过程会进行检查,并在全部通过时插入值。

我尝试在我的SELECT语句中调用该存储过程,但它不起作用。

SELECT field1, field2, myproc(field1, field2)

from MYTABLE.

这种代码是无法正常工作的。

我认为可以使用游标来解决,但我想避免使用游标。 我正在寻找最简单的解决方案。

各位大佬,有什么想法吗?

3个回答

33

使用PL/SQL循环:

BEGIN
   FOR c IN (SELECT field1, field2 FROM mytable) LOOP
       my_proc(c.field1, c.field2);
   END LOOP;
END;

9

SQL只能在投影中使用函数:它需要返回值的东西。因此,您需要编写一些函数。这是坏消息。好消息是,您可以重复使用存储过程中的所有投资。

这是一个强制执行完全公正业务规则的过程:只有经理才能拥有高薪水。

SQL> create or replace procedure salary_rule
  2      ( p_sal in emp.sal%type
  3        , p_job in emp.job%type)
  4  is
  5      x_sal exception;
  6  begin
  7      if p_sal > 4999 and p_job != 'MANAGER' then
  8          raise x_sal;
  9      end if;
 10  exception
 11      when x_sal then
 12          raise_application_error(-20000, 'Only managers can earn that much!');
 13  end salary_rule;
 14  /

Procedure created.

SQL>

由于它是一个过程,我们不能在SELECT语句中使用它;我们需要将其封装在函数中。这个函数只调用存储过程。它返回输入参数P_SAL。换句话说,如果薪水有效(根据规则),它将被返回。否则,函数将重新抛出存储过程的异常。

SQL> create or replace function validate_salary
  2      ( p_sal in emp.sal%type
  3        , p_job in emp.job%type)
  4      return emp.sal%type
  5  is
  6  begin
  7      salary_rule(p_sal, p_job);
  8      return p_sal;
  9  end validate_salary;
 10  /

Function created.

SQL>

这个函数必须返回一个值,我们想要将其插入到我们的表中。它不能返回一些无意义的短语,比如“工资还行”。此外,如果我们想要验证两个列,我们需要为每个列编写单独的函数,即使它们之间存在关系并且我们使用相同的存储过程来验证它们。DETERMINISTIC 关键字可以很好地解决这个问题。

以下是测试内容:水管工不能赚取5000个斯邦利克......

SQL> insert into emp
  2      (empno
  3      , ename
  4      , job
  5      , deptno
  6      , sal )
  7  select
  8      emp_seq.nextval
  9      , 'HALL'
 10      , 'PLUMBER'
 11      , 60
 12      , validate_salary(5000, 'PLUMBER')
 13  from dual
 14  /
    , validate_salary(5000, 'PLUMBER')
      *
ERROR at line 12:
ORA-20000: Only managers can earn that much!
ORA-06512: at "APC.SALARY_RULE", line 12
ORA-06512: at "APC.VALIDATE_SALARY", line 7


SQL>

...但是管理者可以(因为他们值得):

SQL> insert into emp
  2      (empno
  3      , ename
  4      , job
  5      , deptno
  6      , sal )
  7  select
  8      emp_seq.nextval
  9      , 'HALL'
 10      , 'MANAGER'
 11      , 60
 12      , validate_salary(5000, 'MANAGER')
 13  from dual
 14  /

1 row created.

SQL>

请注意,抛出的异常对于此操作至关重要。我们不能在SQL语句中编写一些奇怪的IF SALARY IS VALID THEN INSERT逻辑。因此,如果存储过程没有引发异常,而是返回一些软弱的错误状态,则包装函数将不得不解释输出并抛出自己的异常。

实际上,我的存储过程执行插入操作。因此,我无法使用插入选择语句。 - CC.

0

在SELECT语句中无法使用存储过程,但可以使用函数。

我理解您正在调用SP中的插入操作,因此请注意不能在函数体中使用INSERT / UPDATE。但是,如果您需要进行一些检查,则可以使用函数来执行这些检查,并在SELECT语句中使用该函数。


是的,这将是最终解决方案,但我想使用现有的SP,因为它是一个大项目的一部分,我不想做新的功能。这样会更难维护。 - CC.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接