使用引用游标输出动态执行存储过程

Dynamically execute a stored procedure with reference cursor output

我有这样一个包裹:

CREATE OR REPLACE PACKAGE PKG_EXAMPLE
IS
  PROCEDURE SP_EXAMPLE_1 (inVal IN VARCHAR2, outCur OUT SYS_REFCURSOR);
  PROCEDURE SP_EXAMPLE_2 (inVal IN VARCHAR2, outCur OUT SYS_REFCURSOR);
  PROCEDURE SP_EXAMPLE_N (inVal IN VARCHAR2, outCur OUT SYS_REFCURSOR);
  PROCEDURE SP_NON_CURSOR_EXAMPLE (inVal IN VARCHAR2, outVal OUT VARCHAR2);
END PKG_EXAMPLE;

CREATE OR REPLACE PACKAGE BODY PKG_EXAMPLE
AS
  --for brevity, only showing one relevant procedure
  PROCEDURE SP_EXAMPLE_N (inVal IN VARCHAR2, outCur OUT SYS_REFCURSOR)
  IS
  BEGIN
    OPEN outCur FOR SELECT something FROM somewhere WHERE value = inVal;
  END SP_EXAMPLE_N;

END PKG_EXAMPLE;

在运行时,我正在遍历一些记录,我想动态调用此包中的过程(仅具有 outCur OUT SYS_REFCURSOR 光标输出的过程)。出于 演示 目的,我包含了 SP_NON_CURSOR_EXAMPLE 以表明我可以这样调用它:

DECLARE
  outVal  VARCHAR2(100);
BEGIN

  FOR rec IN (SELECT 'SP_NON_CURSOR_EXAMPLE' as spName, inData FROM table_name) LOOP

    EXECUTE IMMEDIATE 'CALL PKG_EXAMPLE.' || rec.spName || '(''' || rec.inData || ''', :myResult)'
    USING OUT outVal;

  END LOOP;

END;

这行得通。但是对于具有 outCur OUT SYS_REFCURSOR 游标输出的过程,我该如何做呢?我实际上并不需要游标结果或关心它们是什么,我只是想知道游标是否 returned > 0 结果。我想要这样的东西:

DECLARE
  crs  SYS_REFCURSOR;
  cnt  NUMBER;
BEGIN

  FOR rec IN (SELECT spName, inData FROM table_name) LOOP

    EXECUTE IMMEDIATE 'CALL PKG_EXAMPLE.' || rec.spName|| '(''' || rec.inData|| ''', :myResult)'
    USING OUT crs;

    cnt := crs%ROWCOUNT; -- this is what I need

  END LOOP;

END;

%ROWCOUNT 始终为零。我相信我必须 FETCH 游标才能检查它是否 returned 结果,但我不知道游标将 return 是什么列或类型,所以我不知道确定我能拿到什么。

可能不是最好的方法,但我找到了一个可行的解决方案...

DECLARE
  crs    SYS_REFCURSOR;
  crsID  NUMBER;
  cnt    NUMBER  :=  0;
BEGIN

  FOR rec IN (SELECT spName, inData FROM table_name) LOOP

    EXECUTE IMMEDIATE 'CALL PKG_EXAMPLE.' || rec.spName|| '(''' || rec.inData|| ''', :myResult)'
    USING OUT crs;

    crsID:= DBMS_SQL.TO_CURSOR_NUMBER(crs);
    cnt := 0;

    WHILE DBMS_SQL.FETCH_ROWS(crsID) > 0 
    LOOP
      cnt := cnt + 1;
    END LOOP;

  END LOOP;

END;