Oracle Sendig显式游标作为过程参数
我有以下代码。有一个外部过程具有内部的_过程,用于处理游标(将数据从游标连接到m(消息)变量)。我可以打开游标并将引用发送到内部过程进行处理,如: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
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;