PLSQL之游标类型

本文详细介绍了PLSQL中游标的基本概念及使用方法,并通过一个具体示例展示了如何定义、打开、提取和关闭显式游标,适用于需要从数据库获取多行记录并逐条处理的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上一篇博客讲到了列类型,这篇就写下最最常用的PLSQL游标类型。游标:简单的说,我的理解就是行数据的集合,什么场景要用到呢?例如你要查询某个客户的信息,这个客户在数据库有多行的信息返回,但是在数据库处理海量的数据会比直接返回服务器端语言去解析再处理会更加方便(例如Java调用),我们查询到数据后,仍然需要遍历数据库查询到的数据,再处理,最后再返回到调用方。这时候,我们就需要用到这个游标。

如下给个简单的例子,如果有疑问可以留言,我会回复。

--显式游标的demo
--1,定义显式游标。2、打开游标。3、提取游标。4、关闭游标

--查询80号部门的员工信息
DECLARE
 CURSOR cursor_emp IS SELECT * FROM employees WHERE department_id = 60;
 v_emp employees %ROWTYPE;


BEGIN
  --OPEN cursor_emp;
  --FETCH cursor_emp INTO v_emp;
  
 /* WHILE cursor_emp%FOUND LOOP
    dbms_output.put_line(v_emp.employee_id||'---'||v_emp.last_name||'---'||v_emp.department_id);
     FETCH cursor_emp INTO v_emp;
  END LOOP;*/
  
  FOR v_emp IN cursor_emp LOOP
    dbms_output.put_line(v_emp.employee_id||'---'||v_emp.last_name||'---'||v_emp.department_id);
    END LOOP;
   
-- CLOSE cursor_emp; 
--EXCEPTION 
--游标的for循环自动进行游标的打开、提取、关闭
END;

<think>我们正在处理关于PL/SQL中判断游标是否为空的问题。根据用户的问题,他想要知道如何在PL/SQL中判断游标是否返回空值。我们需要参考提供的引用内容,并结合PL/SQL知识来回答。引用[1]提到了在PL/SQL中判断查询结果是否为空,并指出使用count(*)会增加额外查询,特别是在循环中效率低下。引用[2]介绍了隐式游标,并说明可以通过FOR循环遍历隐式游标。在PL/SQL中,游标分为显式游标和隐式游标。判断游标是否为空,通常有两种情况:1.显式游标:我们定义并打开的游标。2.隐式游标:通常用于FOR循环或执行单行查询。针对显式游标,我们可以使用游标的属性来判断是否为空。游标属性包括:-`%FOUND`:如果游标中至少有一行数据,则返回TRUE。-`%NOTFOUND`:如果游标中没有数据,则返回TRUE。-`%ISOPEN`:判断游标是否打开。-`%ROWCOUNT`:返回当前游标中已经取出的行数。因此,对于显式游标,我们可以这样判断:```plsqlDECLARECURSORcur_empISSELECT*FROMemployeesWHEREdepartment_id=999;--假设这个部门不存在v_empemployees%ROWTYPE;BEGINOPENcur_emp;FETCHcur_empINTOv_emp;IFcur_emp%NOTFOUNDTHENDBMS_OUTPUT.PUT_LINE('游标为空');ELSE--处理数据DBMS_OUTPUT.PUT_LINE('有数据');ENDIF;CLOSEcur_emp;END;```但是,上面的代码只处理了第一行。如果我们想判断整个游标是否为空,那么只需要在第一次FETCH之后检查`%NOTFOUND`即可。因为如果第一次FETCH就没有数据,那么游标就是空的。另外,我们也可以使用游标的`%ROWCOUNT`属性,当FETCH之后,如果`%ROWCOUNT`为0,则说明没有数据。但通常我们使用`%NOTFOUND`。对于隐式游标,通常我们使用FOR循环,它会自动处理游标的打开、获取和关闭。如果我们想知道隐式游标是否有数据,可以在循环后使用`SQL%ROWCOUNT`(注意,这是针对最近执行的SQL语句的属性)。例如:```plsqlBEGINFORemp_recIN(SELECT*FROMemployeesWHEREdepartment_id=999)LOOP--处理每一行DBMS_OUTPUT.PUT_LINE(emp_rec.employee_id);ENDLOOP;--如果SQL%ROWCOUNT为0,则说明没有数据IFSQL%ROWCOUNT=0THENDBMS_OUTPUT.PUT_LINE('没有找到任何记录');ENDIF;END;```但是注意,在隐式游标的FOR循环中,如果循环体一次都没有执行,则说明游标为空。所以我们可以使用一个变量来标记是否进入过循环:```plsqlDECLAREv_countNUMBER:=0;BEGINFORemp_recIN(SELECT*FROMemployeesWHEREdepartment_id=999)LOOPv_count:=v_count+1;--处理每一行DBMS_OUTPUT.PUT_LINE(emp_rec.employee_id);ENDLOOP;IFv_count=0THENDBMS_OUTPUT.PUT_LINE('没有记录');ENDIF;END;```或者,我们可以在循环外部使用`SQL%ROWCOUNT`,但是要注意,在隐式游标的FOR循环中,循环结束后游标已经关闭,但是`SQL%ROWCOUNT`仍然会返回从游标中取出的行数。但是,在循环中如果使用`SQL%ROWCOUNT`,它会返回当前已经取出的行数。在循环结束后,我们可以直接使用:```plsqlBEGINFORemp_recIN(SELECT*FROMemployeesWHEREdepartment_id=999)LOOP--处理每一行NULL;ENDLOOP;IFSQL%ROWCOUNT=0THENDBMS_OUTPUT.PUT_LINE('没有记录');ENDIF;END;```注意:`SQL%ROWCOUNT`在循环结束后会返回总行数。但是,如果循环中使用了`EXIT`提前退出,那么`SQL%ROWCOUNT`可能不会等于总行数。所以,如果只是判断是否为空,那么在循环结束后检查`SQL%ROWCOUNT`是否为0是可行的。另外,对于单行查询,我们可以使用SELECTINTO,如果查询没有返回行,则会抛出`NO_DATA_FOUND`异常,如果返回多行则会抛出`TOO_MANY_ROWS`异常。所以,我们可以通过异常处理来判断:```plsqlDECLAREv_empemployees%ROWTYPE;BEGINBEGINSELECT*INTOv_empFROMemployeesWHEREdepartment_id=999;EXCEPTIONWHENNO_DATA_FOUNDTHENDBMS_OUTPUT.PUT_LINE('没有找到记录');END;END;```综上所述,判断游标是否为空的方法取决于游标类型和使用方式。根据用户的问题,他可能更关心显式游标。因此,我们给出显式游标的判断方法。另外,引用[1]中提到避免使用count(*)来避免额外查询,所以我们给出的方法也应该避免使用count(*)。最后,我们生成相关问题。</think>### 在 PL/SQL 中判断游标是否为空的实现方法 在 PL/SQL 中判断游标是否返回空值,可通过游标属性直接实现,无需额外查询。以下是三种常用方法: #### 方法 1:使用显式游标的 `%NOTFOUND` 属性(推荐) ```plsql DECLARE CURSOR emp_cur IS SELECT * FROM employees WHERE department_id = 999; -- 无数据的查询 emp_rec employees%ROWTYPE; BEGIN OPEN emp_cur; FETCH emp_cur INTO emp_rec; IF emp_cur%NOTFOUND THEN -- 判断首次获取是否为空 DBMS_OUTPUT.PUT_LINE('游标结果为空'); ELSE DBMS_OUTPUT.PUT_LINE('游标包含数据'); END IF; CLOSE emp_cur; END; ``` #### 方法 2:使用 `%ROWCOUNT` 属性 ```plsql DECLARE CURSOR dept_cur IS SELECT * FROM departments WHERE location_id = 0; -- 空结果集 BEGIN OPEN dept_cur; IF dept_cur%ROWCOUNT = 0 THEN -- 检查获取前的行数 DBMS_OUTPUT.PUT_LINE('游标打开时为空'); END IF; -- 需实际 FETCH 后获取准确行数 CLOSE dept_cur; END; ``` #### 方法 3:隐式游标结合 `SQL%ROWCOUNT` ```plsql BEGIN FOR rec IN ( SELECT * FROM jobs WHERE min_salary > 100000 -- 空结果查询 ) LOOP NULL; -- 处理数据 END LOOP; IF SQL%ROWCOUNT = 0 THEN -- 循环结束后检查影响行数 DBMS_OUTPUT.PUT_LINE('隐式游标结果为空'); END IF; END; ``` ### 关键说明 1. **游标属性**: - `%NOTFOUND`:首次 `FETCH` 后返回 `TRUE` 表示无数据 - `%ROWCOUNT`:返回当前已获取的行数(打开游标后立即检查为 0) - `SQL%ROWCOUNT`:适用于隐式游标,返回最近 SQL 语句影响的行数 2. **性能优势**: 直接使用游标属性避免了 `COUNT(*)` 的额外查询,尤其在大数据量或循环中可显著提升效率[^1]。 3. **注意事项**: - 显式游标需先 `OPEN` 再 `FETCH` 后才能准确判断 - 隐式游标需在循环结束后检查 `SQL%ROWCOUNT` - 游标关闭后属性不可用 > **最佳实践**:对于显式游标,推荐使用 `%NOTFOUND` 进行首次 `FETCH` 后的空值判断,这是最直接高效的方法[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值