在退出存储过程之前检测空游标

时间:2018-03-31 20:36:21

标签: oracle exception cursor

我有以下声明:

OPEN PARAM_RS FOR
SELECT *
FROM my_table
WHERE my_NUMBER = param_number;

我怎样才能准确地"测试PARAM_US,这样我可以执行另一个语句,如果它是空的吗? 我仍然需要将PARAM_US作为OUT参数返回。

我试过了

if (PARAM_RS%rowcount = 0) THEN...

但即使结果集中有行,此测试也是正面的。

我也尝试使用NO_DATA_FOUND异常,但它没有被触发。

谢谢!

3 个答案:

答案 0 :(得分:1)

你必须从光标获取才能找到是否存在某些内容。看看下面的例子:

{
    _id:5ab94cdb6b106375b6843358   
    credit:
    Array 
0:
    Object
    type:"mastercard" 
    currency:"BRL"
    balance:"4627.56"
1:
    Object
    type:"diners-club-enroute"
    currency:"USD"
    balance:"5222.47"
}

db.mydb.find().forEach( function (x) {
x.credit.balance = parseFloat(x.credit.balance);
db.mydb.save(x);
});
db.mydb.aggregate([
{$unwind: "$credit"},
{$group: {_id: "$credit.currency", sumBalance: {$sum: "$credit.balance"}}}
]).forEach(printjson)

<强> [编辑]

如果要重新使用它以获取整个数据集,是的 - 您将不得不再次打开它。否则,第一行(你为了检查光标中是否有东西而取出的那一行)将“丢失”。

以下是一个例子:

SQL> declare
  2    param_rs sys_refcursor;
  3    rec      emp%rowtype;
  4  begin
  5    open param_rs for
  6      select * from emp
  7      where deptno = &par_deptno;
  8    fetch param_rs into rec;
  9    if param_rs%notfound then
 10       dbms_output.put_line('Nothing has been found');
 11    else
 12       dbms_output.put_line('Oh yes, I found something!');
 13    end if;
 14  end;
 15  /
Enter value for par_deptno: 10
Oh yes, I found something!

PL/SQL procedure successfully completed.

SQL> /
Enter value for par_deptno: 87
Nothing has been found

PL/SQL procedure successfully completed.

SQL>

答案 1 :(得分:0)

光标的

%ROWCOUNT属性在打开时将归零,即使结果集中有行也是如此。该属性返回到目前为止提取的行数,因此在第一个FETCH之前它将为零。

同样地,NO_DATA_FOUND例外不会引发OPEN例外情况,FETCH不会返回一行时会引发此异常。

要回答你的问题,我不相信有任何打开光标的测试,以确定它是否为空#34; ,而不是试图从中获取。

答案 2 :(得分:0)

引用游标是指向一块内存的指针:打开它只是将查询与内存空间相关联但不执行它。直到我们执行fetch,我们才知道查询是否会返回任何内容。这没有什么奇怪的,它正是SQL查询的常用方式。

这就是为什么sql%rowcountno_data_found的测试都不起作用的原因:它们在获取后填充。没有办法测试&#34;游标是否会返回记录而不实际尝试。

那么,如何处理没有返回任何记录的游标?正常的行为是允许调用程序处理它。这是通常的实现。通常因为它通常是具有关于当前交易的最多信息的调用程序,因此最好知道该做什么。

这看起来像(full implementation on LiveSQL - free Oracle TechNet account required)

鉴于API ...

create or replace package test1 as
    type cur1 is ref cursor return my_table%rowtype;

    procedure get_param (p_param in number, p_rs out cur1);
    procedure get_def_param (p_rs out cur1);
end;
/

......调用程序与它交互:

declare
    rc test1.cur1;
    rec my_table%rowtype;
begin
    test1.get_param(42, rc);
    fetch rc into rec;
    if rc%notfound then
        close rc;
        test1.get_def_param(rc);
        fetch rc into rec;
    end if;
    dbms_output.put_line('result='||rec.description);
    close rc;
end;
/

但是,如果您真的希望被调用程序处理空结果集,则可以完成。诀窍是在被调用程序中打开一个测试游标,如果没有提取任何内容,则获取默认记录,然后打开带有保证结果集的参数引用游标。

create or replace package test1 as
    type cur1 is ref cursor return my_table%rowtype;
    type nt is table of my_table%rowtype;

    procedure get_param (p_param in number, p_rs out cur1);
end;
/
create or replace package body test1 as


    procedure get_param (p_param in number, p_rs out cur1) is
        rc cur1;
        recs nt;
    begin
        open rc for
             select t.* 
             from my_table t
             where t.my_number = p_param;
        fetch rc bulk collect into recs;
        if recs.count() = 0 then
            close rc;
            open rc for
                select t.* 
                from my_table t
                where t.my_number = 1;
            fetch rc bulk collect into recs;
        end if;
        close rc;
        open p_rs for 
             select * from table(recs);
    end  get_param;

end;
/

现在调用程序更简单:

declare
    rc test1.cur1;
    rec my_table%rowtype;
begin
    test1.get_param(42, rc);
    fetch rc into rec;
    dbms_output.put_line('result='||rec.description);
    close rc;
end;
/