Oracle Sendig显式游标作为过程参数

Oracle Sendig显式游标作为过程参数,oracle,plsql,cursor,Oracle,Plsql,Cursor,我有以下代码。有一个外部过程具有内部的_过程,用于处理游标(将数据从游标连接到m(消息)变量)。我可以打开游标并将引用发送到内部过程进行处理,如: PROCEDURE outer_proc AS m VARCHAR2(2000):=''; cur SYS_REFCURSOR; PROCEDURE inner_proc(cur IN SYS_REFCURSOR,m OUT VARCHAR2) IS firstname VARCHAR2(20); lastname

我有以下代码。有一个外部过程具有内部的_过程,用于处理游标(将数据从游标连接到m(消息)变量)。我可以打开游标并将引用发送到内部过程进行处理,如:

PROCEDURE outer_proc AS

  m VARCHAR2(2000):='';

  cur SYS_REFCURSOR;

  PROCEDURE inner_proc(cur IN SYS_REFCURSOR,m OUT VARCHAR2) IS
    firstname VARCHAR2(20);
    lastname VARCHAR2(20);
  BEGIN
    LOOP
      FETCH cur INTO firstname,lastname;
      EXIT WHEN cur%NOTFOUND;
      m:=m||firstname||' '||lastname;
    END LOOP;
  END;

BEGIN

  OPEN cur FOR SELECT * FROM employees WHERE sallary<1000;
    inner_proc(cur,m);
  CLOSE cur;

  OPEN cur FOR SELECT * FROM employees WHERE sallary>=1000;
    inner_proc(cur,m);
  CLOSE cur;

END;     
程序外部程序组件
m VARCHAR2(2000):='';
当前系统参考光标;
程序内部程序(系统中的当前参考光标,m OUT VARCHAR2)为
名字VARCHAR2(20);
姓氏VARCHAR2(20);
开始
环
取cur到firstname,lastname;
未找到cur%时退出;
m:=m | | | |‘| |姓;
端环;
结束;
开始
从sallary=1000的员工处为SELECT*打开cur;
内部程序(cur,m);
封闭电流;
结束;
但我想将显式游标名称发送到内部过程,并让内部过程打开游标,然后像这样处理它:

PROCEDURE outer_proc AS

  TYPE cur_type IS REF CURSOR;

  m VARCHAR2(2000):='';

  CURSOR c1 IS SELECT * FROM employees WHERE sallary<1000;
  CURSOR c2 IS SELECT * FROM employees WHERE sallary>=1000;

  PROCEDURE inner_proc(cur IN cur_type,m OUT VARCHAR2) IS
    col1 VARCHAR2(20);
    col2 VARCHAR2(20);
  BEGIN
    OPEN cur;
      LOOP
        FETCH cur INTO col1,col2;
        EXIT WHEN cur%NOTFOUND;
        m:=m||col1||' '||col2;
      END LOOP;
    CLOSE cur;
  END;

BEGIN

  inner_proc(c1,m);
  inner_proc(c2,m);

END;     
程序外部程序组件
类型cur_TYPE为REF CURSOR;
m VARCHAR2(2000):='';
光标c1是从sallary=1000的员工中选择*;
程序内部程序(cur IN cur类型,m OUT VARCHAR2)为
col1-VARCHAR2(20);
col2-VARCHAR2(20);
开始
开放cur;
环
将cur放入col1,col2;
未找到cur%时退出;
m:=m | | col1 | |‘| | col2;
端环;
封闭电流;
结束;
开始
内部程序(c1,m);
内部程序(c2,m);
结束;
在我上面的示例中,游标意外地具有相同的
%ROWTYPE
,但内部\u过程无法事先知道这一点。我的内部过程应该接收一个任意游标作为参数,打开它,最后将第一个和第二个游标的列连接到消息

在我在参数中使用SYS_REFCURSOR的第一个代码中,我可能也会将引用发送到不同的游标,所以。。。为什么我必须发送已经打开的游标的引用,我希望打开和关闭游标的过程是内部过程的一部分。我想发送游标的名称,并将开始和结束(当然是遍历)留给内部过程


我怎样才能做到这一点呢?

我看不出有任何理由需要一个内部过程,你可以通过一个独立的过程来实现。将光标传递给过程/函数时,它必须处于打开状态,即不能在内部过程中打开光标

可能是这样(未经测试):

如果过程只有一个返回值,我更喜欢函数而不是过程

您可以这样调用函数:

DECLARE
    cur SYS_REFCURSOR;
    ret VARCHAR2(10000);
BEGIN
    OPEN cur FOR SELECT * FROM employees WHERE salary < 1000;
    ret := process_cursor(cur);

    OPEN cur FOR SELECT * FROM customers WHERE turnover > 1000;
    ret := process_cursor(cur);

END;
CREATE OR REPLACE FUNCTION process_cursor_str(sqlStr IN VARCHAR2) AS VARCHAR2 IS

    cur SYS_REFCURSOR;
    res VARCHAR2(10000);
    ...

BEGIN
    OPEN cur FOR sqlStr;
    curid := DBMS_SQL.TO_CURSOR_NUMBER(cur);
    ...


DECLARE
    ret VARCHAR2(10000);
BEGIN
    ret := process_cursor_str('SELECT * FROM employees WHERE salary < 1000');       
    ret := process_cursor_str('SELECT * FROM customers WHERE turnover > 1000');    
END;
声明
当前系统参考光标;
ret VARCHAR2(10000);
开始
从工资<1000的员工处打开SELECT*的cur;
ret:=进程\光标(cur);
打开营业额>1000的客户的SELECT*cur;
ret:=进程\光标(cur);
结束;
如果坚持在函数内部打开游标,则必须以字符串形式传递查询。可能是这样的:

DECLARE
    cur SYS_REFCURSOR;
    ret VARCHAR2(10000);
BEGIN
    OPEN cur FOR SELECT * FROM employees WHERE salary < 1000;
    ret := process_cursor(cur);

    OPEN cur FOR SELECT * FROM customers WHERE turnover > 1000;
    ret := process_cursor(cur);

END;
CREATE OR REPLACE FUNCTION process_cursor_str(sqlStr IN VARCHAR2) AS VARCHAR2 IS

    cur SYS_REFCURSOR;
    res VARCHAR2(10000);
    ...

BEGIN
    OPEN cur FOR sqlStr;
    curid := DBMS_SQL.TO_CURSOR_NUMBER(cur);
    ...


DECLARE
    ret VARCHAR2(10000);
BEGIN
    ret := process_cursor_str('SELECT * FROM employees WHERE salary < 1000');       
    ret := process_cursor_str('SELECT * FROM customers WHERE turnover > 1000');    
END;
创建或替换函数进程\u游标\u str(VARCHAR2中的sqlStr)作为VARCHAR2
当前系统参考光标;
res VARCHAR2(10000);
...
开始
为sqlStr打开cur;
curid:=DBMS\u SQL.TO\u CURSOR\u NUMBER(cur);
...
声明
ret VARCHAR2(10000);
开始
ret:=进程\光标\ str('从薪资<1000的员工中选择*);
ret:=流程\光标\ str('从营业额>1000的客户中选择*);
结束;

我看不出内部过程的任何原因,您可以通过一个独立的过程来实现它。将光标传递给过程/函数时,它必须处于打开状态,即不能在内部过程中打开光标

可能是这样(未经测试):

如果过程只有一个返回值,我更喜欢函数而不是过程

您可以这样调用函数:

DECLARE
    cur SYS_REFCURSOR;
    ret VARCHAR2(10000);
BEGIN
    OPEN cur FOR SELECT * FROM employees WHERE salary < 1000;
    ret := process_cursor(cur);

    OPEN cur FOR SELECT * FROM customers WHERE turnover > 1000;
    ret := process_cursor(cur);

END;
CREATE OR REPLACE FUNCTION process_cursor_str(sqlStr IN VARCHAR2) AS VARCHAR2 IS

    cur SYS_REFCURSOR;
    res VARCHAR2(10000);
    ...

BEGIN
    OPEN cur FOR sqlStr;
    curid := DBMS_SQL.TO_CURSOR_NUMBER(cur);
    ...


DECLARE
    ret VARCHAR2(10000);
BEGIN
    ret := process_cursor_str('SELECT * FROM employees WHERE salary < 1000');       
    ret := process_cursor_str('SELECT * FROM customers WHERE turnover > 1000');    
END;
声明
当前系统参考光标;
ret VARCHAR2(10000);
开始
从工资<1000的员工处打开SELECT*的cur;
ret:=进程\光标(cur);
打开营业额>1000的客户的SELECT*cur;
ret:=进程\光标(cur);
结束;
如果坚持在函数内部打开游标,则必须以字符串形式传递查询。可能是这样的:

DECLARE
    cur SYS_REFCURSOR;
    ret VARCHAR2(10000);
BEGIN
    OPEN cur FOR SELECT * FROM employees WHERE salary < 1000;
    ret := process_cursor(cur);

    OPEN cur FOR SELECT * FROM customers WHERE turnover > 1000;
    ret := process_cursor(cur);

END;
CREATE OR REPLACE FUNCTION process_cursor_str(sqlStr IN VARCHAR2) AS VARCHAR2 IS

    cur SYS_REFCURSOR;
    res VARCHAR2(10000);
    ...

BEGIN
    OPEN cur FOR sqlStr;
    curid := DBMS_SQL.TO_CURSOR_NUMBER(cur);
    ...


DECLARE
    ret VARCHAR2(10000);
BEGIN
    ret := process_cursor_str('SELECT * FROM employees WHERE salary < 1000');       
    ret := process_cursor_str('SELECT * FROM customers WHERE turnover > 1000');    
END;
创建或替换函数进程\u游标\u str(VARCHAR2中的sqlStr)作为VARCHAR2
当前系统参考光标;
res VARCHAR2(10000);
...
开始
为sqlStr打开cur;
curid:=DBMS\u SQL.TO\u CURSOR\u NUMBER(cur);
...
声明
ret VARCHAR2(10000);
开始
ret:=进程\光标\ str('从薪资<1000的员工中选择*);
ret:=流程\光标\ str('从营业额>1000的客户中选择*);
结束;
(增加强调):

不能将值指定给显式游标、在表达式中使用它、或将其用作正式子程序参数或宿主变量。可以使用游标变量执行这些操作(请参见“”)

因此,在您的示例中,您不能发送显式游标、
c1
c2
——您不能有一个接受显式游标参数的过程

您可以提供一个ref游标作为,正如您已经做的那样。这可能是一个打开的光标,正如您所看到的;或者一个游标变量,然后打开。但是您似乎并不真的希望游标位于过程调用之外,因此这两个过程似乎都不是您想要的

如果您有一个小的自定义游标列表,您可以直接将游标的名称作为字符串传递,然后在过程中使用case语句打开相关的预定义游标:

PROCEDURE outer_proc AS

  m VARCHAR2(2000):='';

  CURSOR c1 IS SELECT first_name,last_name FROM employees WHERE salary<1000;
  CURSOR c2 IS SELECT first_name,last_name FROM employees WHERE salary>=1000;

  PROCEDURE inner_proc(cur_name IN varchar2,m OUT VARCHAR2) IS
    col1 VARCHAR2(20);
    col2 VARCHAR2(20);
  BEGIN
    CASE cur_name
      WHEN 'c1' THEN
        OPEN c1;
        LOOP
          FETCH c1 INTO col1,col2; -- this will only work in the cursor only selects two columns!
          EXIT WHEN c1%NOTFOUND;
          m:=m||col1||' '||col2;
        END LOOP;
        CLOSE c1;
      WHEN 'c2' THEN
        OPEN c2;
        LOOP
          FETCH c2 INTO col1,col2; -- this will only work in the cursor only selects two columns!
          EXIT WHEN c2%NOTFOUND;
          m:=m||col1||' '||col2;
        END LOOP;
        CLOSE c2;
    END CASE;
  END;

BEGIN

  inner_proc('c1',m);
  inner_proc('c2',m);

END;     
/
程序外部程序组件
m VARCHAR2(2000):='';
光标c1为从薪资=1000的员工中选择名字、姓氏;
过程内部进程(当前名称在varchar2中,m OUT varchar2)为
col1-VARCHAR2(20);
col2-VARCHAR2(20);
开始
CASE cur_name
那么什么时候是c1
开c1;
环
将c1取入col1,col2;——这将只在光标仅选择两列时起作用!
未找到c1%时退出;
m:=m | | col1 | |‘| | col2;
端环;
关闭c1;
什么时候是c2
开放c2;