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

时间:2015-07-08 14:56:21

标签: oracle plsql cursor

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

只给出名称(而不是游标引用)是否可以访问游标并循环通过它?

如果这需要使用"立即执行"或类似的,这不是不可能的......(尽管我不太清楚这是如何工作的,但我认为它宣称的任何东西一旦完成就会超出范围)。

提前道歉,这似乎对我来说应该是显而易见的,但我是空白的。

2 个答案:

答案 0 :(得分:1)

考虑到这一点,我认为你的方式是错误的。我将每个“游标”的所有结果联合起来,然后使用“游标名称”消除所有不需要的行(优化程序应该优化掉的行),这样你才能得到你想要的行。像

这样的东西
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)中的一个读取。我们的想法是让每个子查询返回一个具有相同“形状”的行集,为每个列添加NULL AS XXX,而单个子查询不提供这些行。

祝你好运。

答案 1 :(得分:0)

你原来的问题陈述有点模糊,我不清楚你有什么约束以及“其他系统”期望作为回报值。你也可能有一个XY-problem,所以@bobjarvis的答案也可能有一个有效点。

这里的关键问题是在PL / SQL中无法将explicit cursor转换为cursor variable。因此,以下“简单”解决方案是不可能的:

-- 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“动态”打开迭代关闭游标。

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>