我可以通过名称从过程中访问游标吗?

Can I access a cursor from within a procedure by name?

游标名称将作为 varchar2 传入,并且游标本身与过程存在于同一包中。

仅给定名称(而不是游标引用)是否可以访问游标并循环遍历它?

如果这需要使用 "execute immediate" 或类似的东西,那也不是不可能的......(虽然我不太清楚它是如何工作的,但我对它声明的任何内容印象深刻完成后超出范围)。

提前致歉,这对我来说应该是显而易见的,但我一头雾水。

稍微考虑一下,我认为你的做法是错误的。我将每个 "cursors" 的所有结果 UNION 在一起,然后使用 "cursor name" 消除所有不需要的行(优化器应该优化掉这些行),这样你就只能得到你想要的行。所以像

CREATE OR REPLACE PROCEDURE DO_SOMETHING(pin_Cursor_name IN VARCHAR2)
IS
  CURSOR csrFruits IS
    SELECT UPPER(pin_Cursor_name) AS FRUIT_TYPE,
           VARIETY_NAME,
           COLOR,
           SIZE,
           TARTNESS_RATING,
           NULL AS FUZZ_LENGTH,
           ROOTSTOCK,
           NULL AS PEEL_THICKNESS
      FROM APPLES
      WHERE pin_Cursor_name = 'apples'
    UNION ALL
    SELECT UPPER(pin_Cursor_name) AS FRUIT_TYPE,
           VARIETY_NAME,
           COLOR,
           SIZE,
           NULL AS TARTNESS_RATING,
           FUZZ_LENGTH,
           NULL AS ROOTSTOCK,
           NULL AS PEEL_THICKNESS
      FROM PEACHES
      WHERE pin_Cursor_name = 'peaches'
    UNION ALL
    SELECT UPPER(pin_Cursor_name) AS FRUIT_TYPE,
           VARIETY_NAME,
           COLOR,
           SIZE,
           NULL AS TARTNESS_RATING,
           NULL AS FUZZ_LENGTH,
           NULL AS ROOTSTOCK,
           PEEL_THICKNESS
      FROM KUMQUATS
      WHERE pin_Cursor_name = 'kumquats'
    UNION ALL
    SELECT UPPER(pin_Cursor_name) AS FRUIT_TYPE,
           VARIETY_NAME,
           'GREEN' AS COLOR,
           SIZE,
           NULL AS TARTNESS_RATING,
           FUZZ_LENGTH,
           ROOTSTOCK,
           NULL AS PEEL_THICKNESS
      FROM KIWIS
      WHERE pin_Cursor_name = 'kiwis';
BEGIN
  FOR aRow IN csrFruits LOOP
    DBMS_OUTPUT.PUT_LINE(pin_Cursor_name || ' - ' ||
                         aRow.VARIETY_NAME || ', ' ||
                         aRow.COLOR || ', ' ||
                         aRow.SIZE);
  END LOOP;
END DO_SOMETHING;

所以这里我们有一个游标,它将根据输入参数从四个不同的表(APPLES、PEACHES、KUMQUATS 和 KIWIS)中的一个读取。这个想法是让每个子查询 return 具有相同 "shape" 的行集,为每个子查询不提供的每一列添加 NULL AS XXX

祝你好运。

你原来的问题陈述有点含糊,我不清楚你有什么限制以及 "other system" 期望什么作为 return 值。你也可能有一个 XY-problem,所以@bobjarvis 的回答可能也有一个有效的观点。

这里的关键问题是在PL/SQL中无法转换explicit cursor to a cursor variable。因此,以下 "simple" 解决方案是不可能的:

-- pseudo PL/SQL code
cursor cur_a ...
cursor cur_b ...

function get_cursor(p_cur_name varchar2) return sys_refcursor is 
  v_cur sys_refcursor;
begin
  execute immediate 'open v_cur for p_cur_name';
  return v_cur;
end;

v_cur := get_cursor('cur_b');

在下面的示例包中,我假设所有游标都具有相同的结果集结构。我很懒惰,使用了弱游标变量,即使我应该使用强游标变量。包代码应该很容易理解。

至少还有一种可能对您有用的变体 - 将数据批量收集到一个集合中,然后使用其他子例程处理该集合。下面 print(varchar2) 只是演示如何使用 dbms_output.put_line.

打开-迭代-关闭游标 "dynamically"
create or replace package so48 is
  cursor cur_a is
    select 'A1' as val, 1 as id from dual union all
    select 'A2' as val, 2 as id from dual union all
    select 'A3' as val, 3 as id from dual
  ;
  cursor cur_b is
    select 'B1' as val, 4 as id from dual union all
    select 'B2' as val, 5 as id from dual union all
    select 'B3' as val, 6 as id from dual
  ;

  function get_cursor(p_cur_name in varchar2) return sys_refcursor;
  procedure print(p_cur in sys_refcursor);

  procedure print(p_cur_name in varchar2);
end;
/
show errors

create or replace package body so48 is
  function get_cursor(p_cur_name in varchar2) return sys_refcursor is
    v_cur sys_refcursor;
  begin
    case 
      when p_cur_name = 'A' then
        open v_cur for
          select 'A1' as val, 1 as id from dual union all
          select 'A2' as val, 2 as id from dual union all
          select 'A3' as val, 3 as id from dual
        ;
      when p_cur_name = 'B' then
        open v_cur for
          select 'B1' as val, 4 as id from dual union all
          select 'B2' as val, 5 as id from dual union all
          select 'B3' as val, 6 as id from dual
        ;
      else
        null;
    end case;

    return v_cur;
  end;

  procedure print(p_cur in sys_refcursor) is
    v_val varchar2(32767);
    v_id number;
  begin
    loop
      fetch p_cur into v_val, v_id;
      exit when p_cur%notfound;
      dbms_output.put_line('(val = ' || v_val || ')(id = ' || v_id || ')');
    end loop;
  end;

  procedure print(p_cur_name in varchar2) is
    plsql_compilation_error exception;
    pragma exception_init(plsql_compilation_error, -6550);
    v_cur_name constant varchar2(32767) := 'so48.' || p_cur_name;
    v_plsql constant varchar2(32767) :=
      q'[declare
        v_val varchar2(32767);
        v_id number;
      begin
        open ]' || v_cur_name || q'[;
        loop
          fetch ]' || v_cur_name || q'[ into v_val, v_id;
          exit when ]' || v_cur_name || q'[%notfound;
          dbms_output.put_line('(val = ' || v_val || ')(id = ' || v_id || ')');
        end loop;
        close ]' || v_cur_name || q'[;
      end;]';
  begin
    execute immediate v_plsql;
  exception
    when plsql_compilation_error then
      dbms_output.put_line('PL/SQL compilation error');
  end;
end;
/
show errors

例子运行

SQL> exec so48.print(so48.get_cursor('A'))
(val = A1)(id = 1)
(val = A2)(id = 2)
(val = A3)(id = 3)

PL/SQL procedure successfully completed.

SQL> exec so48.print('cur_b')
(val = B1)(id = 4)
(val = B2)(id = 5)
(val = B3)(id = 6)

PL/SQL procedure successfully completed.

SQL>