【问题标题】:Oracle 11g - How to call a function with DML inside of it?Oracle 11g - 如何在其中调用带有 DML 的函数?
【发布时间】:2015-12-19 01:56:47
【问题描述】:

我做了一个类似...的函数

create or replace function
  pile_data 
  (v_id IN NUMBER, v_area IN VARCHAR2, v_cust_id IN NUMBER)
  return VARCHAR2
AS
  rs VARCHAR2(2);
  cur_id NUMBER;
  -- PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
  select if_seq.currVal into cur_id from dual;
  select '00' into rs from dual;   
  insert into IF_WORK
    (id, area, cust_id, rc)
    values 
    (if_tx_seq.nextVal, v_area, v_cust_id, rs);
  update IF_WORK set rc=rs where id = cur_id;
  return rs;  
  exception
    when dup_val_on_index then
      select '01' into rs from dual;
    return rs;
end;

我有两个问题

  1. 如何调用这个函数作为测试?
  2. 是否可以在exception 语句中返回值?

下面的代码是我想要实现的(我用java做的,但必须用PLSQL实现)

public String pile_data(String ... params){
        String rs = "00";
        int cur_id = SEQ.currVal;
        try{
            insert(params);
        }catch(Exception ex){
            //HANDLING ERRORS
            String exceptionName = ex.getClass().getName();
            switch (exceptionName) {
            case "KEY_DUPLICATION":
                rs = "01";
                break;
            case "CONNECTION_TIMEOUT":
                rs = "02";
                break;
            default:
                rollback();
                rs = "99";
                break;
            }
        }finally{
            // UPDATE ORIGINAL TABLE
            update(cur_id, rs);
        }
        return rs;
    }

关于代码的我的条件。

  • 无论如何都必须返回(成功或失败)
  • 无论插入成功与否都要更新

对于 java 代码,我很抱歉,但这是我能解释得最好的。感谢您的回答。 b

======== 编辑

对不起,我没有告诉我失败的原因。 (来自Oracle的错误代码,我自己翻译的消息)

  1. execute pile_data(params ... );。它返回此错误ORA-06550 : it is not a procedure or not defined
  2. select pile_data(params) from dual;。它返回错误ORA-14552: Can not execute DDL, Commit, Rollback which is inside of Query or DML

================= 编辑#2 ================

所以我现在尝试将其更改为具有返回值的过程。 但是,由于调用者需要得到结果,所以我用函数包装。

create or replace procedure
  pile_data 
  (params ... , rs OUT VARCHAR2)
IS 
  cur_id NUMBER;
BEGIN
  select if_seq.currVal into cur_id from dual;
  select '00' into rs from dual;   
  insert into IF_WORK
    (target params ..., rc)
    values 
      (params ..., rs);
  update IF_WORK set rc=rs where tx_id = cur_id;
  -- DBMS_OUTPUT.PUT_LINE(rs); -- it does not work  
  exception
    when dup_val_on_index then
      select '01' into rs from dual;
      -- DBMS_OUTPUT.PUT_LINE(rs);
    when others then 
      rollback;
      select '99' into rs from dual;
      -- DBMS_OUTPUT.PUT_LINE(rs);
end;


create or replace function pile_data_wrapper(params ...)
return varchar2
is
  rs varchar2(2);
begin
  pile_data(params ... , rs);
  return rs;
end;

select pile_data_wrapper(params ... ) from dual;

我还是得到了ORA-14552

我进退两难,一个函数导致错误,一个过程不能返回。 我需要更好的解决方案。

我想要的目标在下面

  • 远程数据库会调用我的函数,我需要返回响应码。
  • 在这个函数中,我必须插入和更新一个表。

谢谢

【问题讨论】:

  • 据我所知,没有办法绕过不允许函数发出 DML 语句的限制。您需要将函数更改为带有OUT 参数的过程才能获得返回值
  • @a_horse_with_no_name 感谢您的回答。但如果你不介意,你能推荐一个返回值的过程的例子吗?谢谢

标签: java oracle function plsql oracle11g


【解决方案1】:

是的,是的:)

为了测试一个功能,您可以 1. 通过将其放入包中将其保存为数据库对象。或者您可以在工作台中使用 execute 或 exec 关键字运行它(我通常在 SQL 开发人员中执行此操作)

(PWLSQL)您始终可以使用 return 关键字在异常块中返回一个值。

(JAVA)你可以编写你自己的继承异常类的类,并编写你自己的返回某个值的方法。

我希望这会有所帮助。

【讨论】:

  • 感谢您的回答。我很高兴我可以在exception 子句中返回值。所以就像你说的那样,我把上面一个打包成一个包,然后打电话给select PKG_NAME.FUNC_NAME(params ...) from dual。现在我有ORA-14552 错误。我怎样才能解决这个问题?多帮帮我:D
  • 好吧,ORA14552 问题意味着您在程序中的某个点发出提交或回滚,其中它被阻止或不允许。如果我查看您的代码,我发现您的 pragma 指令已被注释,您是否尝试过使用“PRAGMA AUTONOMOUS_TRANSACTION;”将其变为自主事务? ?
  • 我不能说我解决了这个问题,但我发现了一些东西。 ORA-14552 在 sqlplus 中运行时不会发生错误。该错误仅发生在 sql developer 中。
【解决方案2】:

我不能说我解决了这个问题,但我发现了一些东西。当我在 sqlplus 中运行它时,不会发生 ORA-14552 错误。该错误仅发生在 sql developer 中。

下面是我在 SQLPlus(终端) 中运行它的方式

    SQL> var tmp varchar2(2);                          -- define a variable
    SQL> execute :tmp := PILE_DATA@DB_LINK('a', 1, 2); -- set value to variable
    SQL> print tmp;                                    -- print the result for checking

================================================ =

其他选项是制作一个处理异常的包装函数。

即制作一个没有异常处理的函数,如下所示。

FUNCTION CREATEWITH(v_id IN NUMBER,v_value1 IN VARCHAR2,v_value2 IN NUMBER) 
return Number
Is
BEGIN
    insert into DEVICE_BALJU(id, value1, value2)
    values (v_id, v_value1, v_value2);

return SQL%ROWCOUNT ;
END CREATEWITH; 

并构建一个处理异常的包装类

create or replace FUNCTION "FN_WRAPPER" (v_id IN VARCHAR2,v_value1 IN NUMBER,v_value2 IN NUMBER)
RETURN Varchar2
is
  rs VARCHAR2(2);
  tmp NUMBER;
begin
--    DBMS_OUTPUT.PUT_LINE('Hello!!!');
    rs := '00';
    tmp := createWith(v_id, v_value1, v_value2);
    RETURN rs;

    EXCEPTION
        WHEN OTHERS THEN
          rs := '99';
          RETURN rs; 
END;

这就是我在 final 中避免此错误的方法。

【讨论】:

    猜你喜欢
    • 2011-01-18
    • 2016-09-28
    • 1970-01-01
    • 2011-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-31
    • 2014-05-09
    相关资源
    最近更新 更多