【问题标题】:Oracle Function return varchar2 is ok, but return SYS_REFCURSOR get ORA-14551Oracle 函数返回 varchar2 没问题,但返回 SYS_REFCURSOR 得到 ORA-14551
【发布时间】:2016-07-18 18:52:04
【问题描述】:

工具:Toad 9.7.2.5

我写了 1 个函数,里面有一个插入语句。

我执行命令

SELECT TWO2F_QUERY_TEST ('XX', 'XX') 
  FROM DUAL;

当这个函数返回SYS_REFCURSOR时,我会得到

1,N,*插入 TWO2R063_W1 错误(C1-未使用)**ORA-14551:不能 在查询中执行 DML 操作

当这个函数返回varchar2时,会处理成功

代码:

CREATE OR REPLACE FUNCTION TWO2F_QUERY_TEST
(PI_BUS_ID         IN  VARCHAR2 ,
 PI_TMNL_ID        IN  VARCHAR2 
)RETURN SYS_REFCURSOR IS
--)RETURN VARCHAR2 IS
PO_CURSOR SYS_REFCURSOR;
WK_ACTION VARCHAR2(01) := 'Y';
WK_MSG    VARCHAR2(100);
BEGIN
  BEGIN
    INSERT INTO TWO2R063_W1
      ( R063W1_TITLE   ,
        R063W1_FORWARD
      )
    VALUES             
      ( 'PROGRAM NOT USED' ,
        'XX'            
      )
    ;
  EXCEPTION
    WHEN OTHERS THEN
      WK_ACTION := 'N';
      WK_MSG    := SUBSTR('*INSERT TWO2R063_W1 ERROR(C1-NOT USED)'||SQLERRM, 1, 100);
      GOTO OUTER;
  <<OUTER>> 
  <<ENDRTN>>                                   

  OPEN PO_CURSOR FOR 
    SELECT ROWNUM    AS PO_ROWNUM ,
           WK_ACTION AS PO_ACTION , 
           WK_MSG    AS PO_MSG   
      FROM DUAL
    ;

  RETURN PO_CURSOR;

  --RETURN 'Y';

END TWO2F_QUERY_TEST;

/
SHOW ERROR;
DROP    PUBLIC  SYNONYM TWO2F_QUERY_TEST;
CREATE  PUBLIC  SYNONYM TWO2F_QUERY_TEST FOR TWO2F_QUERY_TEST;
GRANT   EXECUTE ON TWO2F_QUERY_TEST TO GTS_AP_MAINTAIN, EGTS;
/

========================================================
DROP TABLE TWO2.TWO2R063_W1 CASCADE CONSTRAINTS;

CREATE GLOBAL TEMPORARY TABLE TWO2.TWO2R063_W1
(R063W1_TITLE   VARCHAR2(50 BYTE),
 R063W1_FORWARD VARCHAR2(20 BYTE)
)ON COMMIT PRESERVE ROWS NOCACHE;

DROP PUBLIC SYNONYM TWO2R063_W1;
CREATE PUBLIC SYNONYM TWO2R063_W1 FOR TWO2.TWO2R063_W1;
GRANT DELETE, INSERT, SELECT, UPDATE ON TWO2.TWO2R063_W1 TO TWO2_MAINTAIN;
GRANT SELECT ON TWO2.TWO2R063_W1 TO TWO2_QUERY;

【问题讨论】:

  • 在查询中引用函数时,不允许该函数更改数据库状态。因此,如果您的函数执行任何 DML 操作,请不要在查询中使用它。

标签: oracle


【解决方案1】:

在您的第一个 begin 关键字结束之前声明 pragma autonomous_transaction 并查看。

示例

  CREATE OR REPLACE FUNCTION TWO2F_QUERY_TEST
       (PI_BUS_ID         IN  VARCHAR2 ,
        PI_TMNL_ID        IN  VARCHAR2 
       )RETURN SYS_REFCURSOR IS
      --)RETURN VARCHAR2 IS
       PO_CURSOR SYS_REFCURSOR;
       WK_ACTION VARCHAR2(01) := 'Y';
       WK_MSG    VARCHAR2(100);

        PRAGMA AUTONOMOUS_TRANSACTION;
        BEGIN
        -- Your code to insert
        END

【讨论】:

    【解决方案2】:

    我认为问题在于您从 SELECT 调用函数而不是返回类型。现在只需删除 DML 并对其进行测试。 这是我的测试:

    CREATE OR REPLACE FUNCTION TWO2F_QUERY_TEST
    RETURN SYS_REFCURSOR IS
    PO_CURSOR SYS_REFCURSOR;
    BEGIN
    
      OPEN PO_CURSOR FOR 
        SELECT ROWNUM        AS PO_ROWNUM ,
               owner         AS PO_ACTION , 
               table_name    AS PO_MSG   
          FROM all_tables
        ;
    
      RETURN PO_CURSOR;
    END TWO2F_QUERY_TEST;
    /
    
    
    declare 
      cur  SYS_REFCURSOR;
      l_rownum number; 
      l_action varchar2(30);
      l_msg    varchar2(30);
    begin
      cur := TWO2F_QUERY_TEST;
      fetch cur into l_rownum, l_action, l_msg;
      close cur;
      dbms_output.put_line(l_rownum||') '||l_action||'.'||l_msg); 
    end;
    /
    

    这是我的输出:

    1) SYS.DUAL
    

    您的问题在于从 SQL 调用 DML。您有以下选择:

    1) 删除 DML

    2) 不要从 SQL 调用函数

    3) 如果可能,将 DML 包装到自治事务中。

    【讨论】:

      猜你喜欢
      • 2016-05-06
      • 1970-01-01
      • 2021-06-15
      • 2016-01-02
      • 2021-01-24
      • 1970-01-01
      • 1970-01-01
      • 2018-04-23
      • 1970-01-01
      相关资源
      最近更新 更多