8.3.3 隐式游标的属性

隐式游标的属性和显式游标的属性具体表示含义有区别,但属性种类没有变。下面列出隐式游标的属性。

❑%ISOPEN属性:该属性永远返回FALSE,它由Oracle自己控制。

❑%FOUND属性:此属性可以反应DML操作是否影响到了数据,当DML操作对数据有影响时该属性为TRUE,否则为FALSE。也可以反映出SELECT INTO语句是否返回了数据,当有数据返回时该属性为TURE。

❑%NOTFOUND属性:与%FOUND属性相反,当DML操作没有影响数据以及SELECT INTO没有返回数据时该属性为TRUE,其他为FALSE。

❑%ROWCOUNT属性:该属性可以反映出DML操作对数据影响的数量。

下面利用几个示例来了解以上4个属性的具体使用方法。

1)隐式游标中的%ISOPEN属性和显式游标中的该属性不同,隐式游标该属性永远为FALSE。

【示例12】隐式游标中%ISOPEN的使用

下面的脚本验证了%ISOPEN属性返回FALSE的特性。


01 DECLARE

02 BEGIN

03 DELETE FROM PRODUCTINFO;

04 IF SQL%ISOPEN THEN

05 DBMS_OUTPUT.PUT_LINE('游标打开!');

06 ELSE

07 DBMS_OUTPUT.PUT_LINE('游标未打开!');

08 END IF;

09 END;


【执行效果】

以上脚本执行后输出结果如下:


游标未打开!


由执行结果可以看出此属性的值是FALSE。当第3行执行完成后它由Oracle自动关闭。

2)%FOUND属性在INSERT、UPDATE、DELETE执行对数据有影响时会返回TRUE,而SELECT INTO语句只要有数据返回,该属性就为TRUE。

【示例13】隐式游标中%FOUND的使用

具体代码如下:


01 DECLARE

02 cur_productname productinfo.Productname%TYPE;

03 cur_productprice productinfo.Productprice%TYPE;

04 BEGIN

05 SELECT productname,productprice INTO cur_productname,cur_productprice

06 FROM PRODUCTINFO;

07

08 EXCEPTION

09 WHEN TOO_MANY_ROWS THEN

10 IF SQL%FOUND THEN

11 DBMS_OUTPUT.PUT_LINE('%FOUND为TRUE');

12 DELETE FROM PRODUCTINFO WHERE productid='00000000';

13 IF SQL%FOUND THEN

14 DBMS_OUTPUT.PUT_LINE('删除数据!');

15 END IF;

16 END IF;

17

18 END;


【代码解析】

❑第1~4行读者理解应该不会有问题,这里不再介绍。

❑第5~6行利用SELECT INTO语句向变量中保存数据,但此语句会返回多条数据,也就是说会引发异常。

❑第9行是此语句可能引发的异常,当返回多条数据时会出现TOO_MANY_ROWS异常,脚本会进入THEN后面的代码流程。

❑第10行在发生TOO_MANY_ROWS异常时检测%FOUND是否为TRUE,如果为TRUE则执行THEN后面的脚本。

❑第12行表示当%FOUND为TRUE时,执行该删除脚本。

❑第13行继续判断该删除脚本产生的游标的%FOUND属性,如果为TRUE,则会执行第14行脚本。

❑第15~18行读者可以自行找到其对应的开始标识。

【执行效果】

执行效果如下:


%FOUND为TRUE


由此脚本的执行效果可以看出该属性的使用方法以及特性,第12行的删除语句由于数据库中没有符合WHERE后的条件的记录,所以它并没有影响任何数据,此时的%FOUND为FALSE,第14行脚本也就没有得到执行。

注意 在SELECT INTO语句中%FOUND不会因语句是否发生异常而改变,只要有返回值该属性就为TRUE。但有异常发生时,执行流程会马上发生改变。也就是说,在异常代码外检查该属性有可能得不到有效执行。第13行的%FOUND是第12行删除语句游标的属性,这一点读者需要注意。

3)%NOTFOUND属性和%FOUND属性在逻辑上是相反的,这里不再给出具体的示例。读者把%FOUND属性的示例稍作修改即可。

4)与显式游标不同的是隐式游标中%ROWCOUNT属性反映了DML操作影响的数据数量,而SELECT INTO语句如果发生TOO_MANY_ROWS异常,那么此属性依然是1,而不是实际符合要求的记录数。

【示例14】隐式游标中%ROWCOUNT的使用

具体代码如下:


01 DECLARE

02 cur_productname productinfo.Productname%TYPE;

03 cur_productprice productinfo.Productprice%TYPE;

04 cur_count varchar(8);

05 BEGIN

06 SELECT productname,productprice INTO cur_productname,cur_productprice

07 FROM PRODUCTINFO;

08

09 EXCEPTION

10 WHEN NO_DATA_FOUND THEN

11 DBMS_OUTPUT.PUT_LINE(SQL%ROWCOUNT);

12 DBMS_OUTPUT.PUT_LINE('没有数据!');

13

14 WHEN TOO_MANY_ROWS THEN

15 cur_count:=SQL%ROWCOUNT;

16 DBMS_OUTPUT.PUT_LINE('SQL%ROWCOUNT值是:'||cur_count);

17 UPDATE PRODUCTINFO SET PRODUCTINFO.productname='';

18 DBMS_OUTPUT.PUT_LINE('修改脚本影响记录数:'||SQL%ROWCOUNT);

19 ROLLBACK;

20 DBMS_OUTPUT.PUT_LINE('脚本回滚后:'||SQL%ROWCOUNT);

21 END;


【代码解析】

❑此脚本运行时会出现TOO_MANY_ROWS异常,然后进入异常块内部。

❑第4行声明一个类型为varchar类型的变量,用此变量存放%ROWCOUNT的值。

❑第15行表示发生异常时把%ROWCOUNT的值保存到变量cur_count中,通过第16行的输出可以测试保存是否成功。

❑第17行修改表PRODUCTINFO中数据。

❑第18行输出修改语句影响的记录数。

❑第19行事务回滚。

❑第20行输出事务回滚后%ROWCOUNT属性值。

【执行效果】

执行效果如下:


SQL%ROWCOUNT值是:1

修改脚本影响记录数:7

修改脚本影响记录数:0


通过以上执行效果可以看到,使用变量cur_count保存%ROWCOUNT值是成功的,开发过程中用户经常使用此方式保留%ROWCOUNT值,以便控制流程时使用。而当SELECT INTO语句发生TOO_MANY_ROWS异常时,%ROWCOUNT属性依然返回1条记录,而不是实际的记录数目。这是需要注意的。

注意 %ROWCOUNT属性和事务没有关系,即使事务回滚,它的值也不会变成上次操作的值,这可以从第20行的输出结果看出来。