【问题标题】:Error ORA-00904 while calling procedure inside package using EXECUTE IMMEDIATE使用 EXECUTE IMMEDIATE 调用包内的过程时出现错误 ORA-00904
【发布时间】:2021-11-01 02:56:36
【问题描述】:

我正在开发一个 PLSQL 包,该包调用另一个 PLSQL 包,该包返回单独的结果(即 OUT 变量),如下所示:

  • (1) SYS_REFCURSOR
  • (1) 号码
  • (1) VARCHAR2

这是我构建的dbfiddle

链接的dbfiddle的完整代码:

/* Main table - it contains the data to use in a cursor: */
CREATE TABLE tpos_retbenf
(
id_serial NUMBER (9,0),
serial_nmb NUMBER(12,0)
);
/* Destination of the records detected on "tpos_retbenf": */
CREATE TABLE tbl_debug 
(
msg_text VARCHAR2(1000),
record_date DATE
);
/* Add values to the main table: */
INSERT INTO tpos_retbenf (id_serial, serial_nmb) 
VALUES (1, 202108311635);
/* Package that contains the code to execute: */
create or replace PACKAGE                 PCK_POS_UNO is

PROCEDURE SP_POS_UNO (ID_RECORD IN NUMBER,
                                  CUR_RET_BENF OUT SYS_REFCURSOR,
                                  IDERROR OUT NUMBER,
                                  DSERROR OUT VARCHAR2);

end PCK_POS_UNO;
/
create or replace PACKAGE BODY                 PCK_POS_UNO is

/* This is the procedure that returns results in separated variables: */
PROCEDURE SP_POS_UNO (ID_RECORD IN NUMBER,
                                  CUR_RET_BENF OUT SYS_REFCURSOR,
                                  IDERROR OUT NUMBER,
                                  DSERROR OUT VARCHAR2) AS


v_temp number(6) := 0;
v_S varchar2(1) := 'S';

BEGIN

    if ID_RECORD is null or ID_RECORD <= 0 then
      IDERROR := -1;
      DSERROR := 'Id no valido para la operacion';
      goto finalizar;
    end if;

    select count(1) into v_temp
    from tpos_retbenf r
    where r.id_serial = ID_RECORD;

    if v_temp = 0 then
      IDERROR := -1;
      DSERROR := 'Id no encontrado';
      goto finalizar;
    end if;

    OPEN CUR_RET_BENF FOR
    select r.id_serial, r.serial_nmb
    from tpos_retbenf r 
     where r.id_serial = ID_RECORD;


<<finalizar>>
 null;

END SP_POS_UNO;

END PCK_POS_UNO;
/
/* Package that calls the "SP_POS_UNO" procedure from the "PCK_POS_UNO" package: */
create or replace PACKAGE PKG_BH_ONLINE_INFORMATION IS
  PROCEDURE ONLINENOVELTYBEN
   (
      V_NID_DEV IN NUMBER,  
        CV_1 IN OUT SYS_REFCURSOR
    );
END PKG_BH_ONLINE_INFORMATION;
/
create or replace PACKAGE BODY PKG_BH_ONLINE_INFORMATION IS 
PROCEDURE ONLINENOVELTYBEN
(
  V_NID_DEV IN NUMBER,
    CV_1 IN OUT SYS_REFCURSOR
) IS
    
    V_USER VARCHAR2(10 CHAR) := 'INTERNET';
    V_QUERY VARCHAR2(10000 CHAR);
    -- Variables:
    V_OUT_CUR_RET_BENF SYS_REFCURSOR;
    V_OUT_IDERROR NUMBER;
    V_OUT_DSERROR VARCHAR2(10000 CHAR);
BEGIN

    /* 
        Here, the "PCK_POS_UNO.SP_POS_UNO" is called 
        from "PKG_BH_ONLINE_INFORMATION" as follows:
    */
    V_QUERY := 'SELECT APPLICATION_POS.PCK_POS_UNO.SP_POS_UNO(:V_NID_DEV, :V_OUT_CUR_RET_BENF, :V_OUT_IDERROR, :V_OUT_DSERROR) FROM DUAL';
    EXECUTE IMMEDIATE V_QUERY INTO V_OUT_CUR_RET_BENF, V_OUT_IDERROR, V_OUT_DSERROR USING V_NID_DEV, V_OUT_CUR_RET_BENF, V_OUT_IDERROR, V_OUT_DSERROR ;
    
    /*
      An this error occurs:
      Error: ORA-00904: "PCK_POS_UNO"."SP_POS_UNO": invalid identifier - StackTrace: ORA-06512: in line 24
    */

    -- After getting the results in (V_OUT_CUR_RET_BENF, V_OUT_IDERROR, V_OUT_DSERROR) variables, 
    -- a LOOP is executed for retrieve the records in "V_OUT_CUR_RET_BENF" cursor...
    -- It doesn't continue here due to error shown above.

END ONLINENOVELTYBEN;

END PKG_BH_ONLINE_INFORMATION;
/

当下面的代码要执行时:

V_QUERY := 'SELECT APPLICATION_POS.PCK_POS_UNO.SP_POS_UNO(:V_NID_DEV, :V_OUT_CUR_RET_BENF, :V_OUT_IDERROR, :V_OUT_DSERROR) FROM DUAL';
EXECUTE IMMEDIATE V_QUERY INTO V_OUT_CUR_RET_BENF, V_OUT_IDERROR, V_OUT_DSERROR USING V_NID_DEV, V_OUT_CUR_RET_BENF, V_OUT_IDERROR, V_OUT_DSERROR ;

错误提示:

错误:ORA-00904:“APPLICATION_POS”。“PCK_POS_UNO”。“SP_POS_UNO”:无效标识符 - StackTrace:ORA-06512:在第 24 行


到目前为止我已经尝试过:

  • 搜索 ORA-00904 错误 - 在 this answer 中说“对查询中涉及的对象的适当权限” - 我分享了这一点,但是,我不知道如何论证这个选项( 因为我可以对那个表做一个简单的SELECT 并且结果是显示出来的,因此,他们可能不接受这个论点)。与此论点相关,我无法列出 PCK_POS_UNO 包“因为 OWNER 与我通常使用的不同(即 APPLICATION)”。
  • 我复制了这个包/过程,并且能够通过 SQL Developer 执行过程/包 - 查看屏幕截图,但是,同样的错误 ORA-00904 发生了。

包的执行截图:

结果:

  • 更改调用具有OUT 参数的过程的代码,但是,我无法获得允许编译和执行整个代码的成功组合。

示例 - 全部基于互联网搜索和我自己的“本能”:

(1):在动态sql字符串的末尾添加(;):

V_QUERY := 'SELECT APPLICATION_POS.PCK_POS_UNO.SP_POS_UNO((:V_NID_DEV, :V_OUT_CUR_RET_BENF, :V_OUT_IDERROR, :V_OUT_DSERROR) FROM DUAL;';

(2):删除 OWNER - 在本例中为“APPLICATION_POS”:

V_QUERY := 'SELECT PCK_POS_UNO.SP_POS_UNO(:V_NID_DEV, :V_OUT_CUR_RET_BENF, :V_OUT_IDERROR, :V_OUT_DSERROR) FROM DUAL';

(3):直接调用过程 - 它显示 SP2-0552: bind variable "V_NID_DEV" not declared - 但是,如何?在一个单独的示例中,变量“V_NID_DEV”被声明并具有值“2462013”​​:

PCK_POS_UNO.SP_POS_UNO(:V_NID_DEV, :V_OUT_CUR_RET_BENF, :V_OUT_IDERROR, :V_OUT_DSERROR);

(4):直接调用过程(同时删除点)-在这种情况下,会生成 ORA-01001 - invalid cursor 错误-我认为这没有意义-因为 OUT 光标没有被打开读取或以某种方式操作。

PCK_POS_UNO.SP_POS_UNO(V_NID_DEV, V_OUT_CUR_RET_BENF, V_OUT_IDERROR, V_OUT_DSERROR);

我真的没有想法了——因为我不熟悉这种类型的创建包和在包之间传递值,而且我没有创建这段代码。

有没有办法让这段代码工作?

【问题讨论】:

  • 你不能select 过程从某事中产生结果,因为过程不返回任何东西。所以select proc() from dual 不是一个有效的语法。正确的方法是PCK_POS_UNO.SP_POS_UNO(V_NID_DEV, V_OUT_CUR_RET_BENF, V_OUT_IDERROR, V_OUT_DSERROR);,因为你传递的是 PL/SQL 变量,而不是绑定变量。 4 呢:很难说,什么是错的,因为它按预期工作。检查更正db<>fiddle
  • 另外请提供 minimal 可重现的例子。重新键入所有那些不使用其输入参数的长标识符和嵌​​套过程非常无聊。
  • @astentx,代码就是这样(甚至不是我的),正在处理遗留代码,tbh。
  • 但无论如何,关于特定的重点问题。如果您已经花费了足够的时间进行调试以定位有问题的代码和平,并且可以重现该问题,那么在这种情况下,周围的代码将只有几行。如果您从头开始构建代码,那么您肯定会面临代码不再工作的步骤。在这个特定的情况下,它几乎是在最开始的时候(简单的过程,为select * from dual打开了光标,带有一个输入和输出参数)。
  • @astentx,虽然我创建了一个 minimal 可重现的示例 - 相信我,这是我可以管理的最紧凑的示例。老实说,我感谢您的帮助。如果您想发布答案,我会接受。

标签: oracle plsql plsql-package


【解决方案1】:

包修改为调用过程SP_POS_UNO:

CREATE OR REPLACE PACKAGE BODY PKG_BH_ONLINE_INFORMATION
IS 
  PROCEDURE ONLINENOVELTYBEN(V_NID_DEV IN NUMBER,
                             CV_1      IN OUT SYS_REFCURSOR
                            )
  IS
    V_USER  VARCHAR2(10 CHAR) := 'INTERNET';
    V_QUERY VARCHAR2(10000 CHAR);
    -- Variables:
    V_OUT_CUR_RET_BENF   SYS_REFCURSOR;
    V_OUT_IDERROR        NUMBER;
    V_OUT_DSERROR       VARCHAR2(10000 CHAR);
  BEGIN
      /* 
          Here, the "PCK_POS_UNO.SP_POS_UNO" is called 
          from "PKG_BH_ONLINE_INFORMATION" as follows:
      */
      V_QUERY:='Begin
 PCK_POS_UNO.SP_POS_UNO(:V_NID_DEV, :V_OUT_CUR_RET_BENF, :V_OUT_IDERROR, :V_OUT_DSERROR);
End;';
      --
      EXECUTE IMMEDIATE V_QUERY
      USING     V_NID_DEV, 
            out V_OUT_CUR_RET_BENF, 
            out V_OUT_IDERROR, 
            out V_OUT_DSERROR ;
      Dbms_Output.Put_Line('V_OUT_IDERROR='||V_OUT_IDERROR);
      Dbms_Output.Put_Line('V_OUT_DSERROR='||V_OUT_DSERROR);
      --
      CV_1:=V_OUT_CUR_RET_BENF;
  END ONLINENOVELTYBEN;
  --
END PKG_BH_ONLINE_INFORMATION;

【讨论】:

    猜你喜欢
    • 2020-06-14
    • 1970-01-01
    • 2015-11-17
    • 2015-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多