Oracle中“IN”和“IN OUT”CURSOR参数的区别

Posted

技术标签:

【中文标题】Oracle中“IN”和“IN OUT”CURSOR参数的区别【英文标题】:Difference between "IN" and "IN OUT" CURSOR parameter in Oracle 【发布时间】:2010-08-20 21:59:21 【问题描述】:

来自Oracle: "当你声明一个游标变量作为从游标变量中取数据的子程序的形参时,必须指定IN或IN OUT模式。如果子程序也打开游标变量,你必须指定IN OUT模式。”

但是,我可以编码(只有 OUT 参数):

create or replace procedure mycur_out(mc OUT mycurpkg.mytypecur)  as 
begin
    open mc for select * from mytable; 
end mycur_out;

并且等于(IN OUT 参数)

create or replace procedure mycur_inout(mc IN OUT mycurpkg.mytypecur) 
as
begin
    open mc for select * from table10;
end mycur_inout;

另外,动态光标也可以正常工作:

create or replace procedure mycur_out_ref(mc out mycurpkg.mytyperefcur) 
as
begin
    open mc for 'select * from table10';
end mycur_out_ref;

我已经直接从 oracle 和带有 ADO 的 VB6 测试了这 3 个案例,没有问题。 那么,在那种情况下,IN 只使用“OUT”和“IN OUT”游标参数有什么区别吗?

更新 我问的原因:

我们使用类似的例程读取数据 示例(只需打开 游标)。游标参数 总是“IN OUT”(别问我 为什么,我想弄清楚) 使用 ADO/VB6 调用例程 现在,我们正在尝试使用 JDBC 中的一些例程,但是 适配器显然只接受 OUT 这种情况下的参数。 最后,主要原因,我想改变DB上的游标参数 例程只 OUT,但首先我 想知道络脉效应 的变化。

谢谢!

【问题讨论】:

看代码,不是问题'OUT 和IN OUT 游标参数有什么区别吗?'。没有带有 IN 参数的示例。 好点,JulesLt。我正在更新问题。谢谢! 【参考方案1】:

在您从手册中引用的文本中,请注意它专门谈论“一个子程序从游标变量中获取”。您的示例都没有这样做,因此引用与它们无关。

然而,如果子程序同时打开并从游标变量中获取,那么仅在这种情况下使用OUT 似乎没有任何问题:

SQL> variable c refcursor

SQL> set serveroutput on
SQL> create or replace procedure no_good (c  OUT sys_refcursor)
  2     as
  3        my_dummy  dual.dummy%type;
  4     begin
  5       open c for select dummy from dual union all select dummy from dual;
  6       fetch  c into my_dummy;
  7       dbms_output.put_line( my_dummy );
  8     end;
  9  /

Procedure created.

SQL> exec no_good( :c )
X

PL/SQL procedure successfully completed.

SQL> print c

D
-
X

我认为文本实际上是试图提出两个相互独立的观点。首先,如果您想将任何已经打开的游标变量传递给将从中获取的子程序,则参数必须声明为ININ OUT。其次,如果要将游标变量传递给子程序,然后子程序将打开它,则必须将参数声明为OUTIN OUT。无论您是否真的关心将游标变量的值传回给调用者,这都是正确的:

SQL> create or replace procedure no_good (c  IN sys_refcursor)
  2     as
  3        my_dummy  dual.dummy%type;
  4     begin
  5       open c for select dummy from dual;
  6       fetch  c into my_dummy;
  7       dbms_output.put_line( my_dummy );
  8       close c;
  9     end;
 10  /

Warning: Procedure created with compilation errors.

SQL> show error
Errors for PROCEDURE NO_GOOD:

LINE/COL ERROR
-------- -----------------------------------------------------------------
5/6      PL/SQL: SQL Statement ignored
5/11     PLS-00361: IN cursor 'C' cannot be OPEN'ed

这个错误可以通过更改参数模式来修复,但实际上将游标变量简单地设置为局部变量而不是参数似乎更有意义。

【讨论】:

谢谢戴夫,你明白了。 “......仅在这种情况下使用 OUT 没有任何问题”我试图弄清楚在这种情况下是否强制使用 de“IN OUT”,或者使用“OUT”就足够了。再次感谢。【参考方案2】:

如果我理解正确的问题,不同之处在于,使用 IN OUT 版本,您可以从过程外部传入游标,然后更改该变量(类似于简单数值变量的 OUT 和 IN OUT 之间的区别)。

OUT 参数游标以 NULL 值/关闭游标开始。

IN OUT 参数版本以从外部传入的任何状态开始。

您可能想重试您的过程调用,重复传递相同的游标变量 - OUT 版本应该替换现有值,IN OUT 版本应该在您尝试打开打开的游标的第二轮中给出异常.

IN OUT 方法允许但 OUT 方法不允许的另一件事是根据传入的游标采取行动,并更改返回的游标。

PROCEDURE lp_test2 (mc IN OUT mycurpkg.mytypecur)
IS
  lr table10%ROWTYPE;
BEGIN 
   IF mc%ISOPEN THEN 
      FETCH mc INTO lr;
      IF mc%NOTFOUND THEN
         CLOSE mc;
         /* Switch cursor to alternative table */
         open mc for select * from schema2.table10;
      END IF;
   END IF;
END lp_test2;

我只是在努力想一个你可能想要的真实情况(接受一个游标变量,将其转换回 SQL 语句,附加一些额外的动态 SQL,然后将全部作为同一个游标返回? ?)。

【讨论】:

非常感谢 JulesLT。好例子。就我而言,我只是想知道示例的“IN OUT”参数是否可以仅用“OUT”参数替换。

以上是关于Oracle中“IN”和“IN OUT”CURSOR参数的区别的主要内容,如果未能解决你的问题,请参考以下文章

oracle 存储过程参数介绍 in ,out , in out 以及 执行

如何在oracle存储过程中执行动态sql语句

如何调用具有 IN/OUT 参数并通过 DB Link 返回 BLOB 的 Oracle PL/SQL 函数

oracle存储过程,IN OUT 类型的参数怎么传参数

12.Python操作关系型数据库

Oracle存储过程的语法分析