显式游标必须用 CURSOR 关键字声明,漏写会导致 PLS-00103 编译错误;其本质是用户定义的命名查询,需 OPEN/FETCH/CLOSE 成对使用,循环结束判断应依赖 %NOTFOUND 而非 %ROWCOUNT。
显式游标必须用 CURSOR 关键字声明,不能只写 DECLARE c1
oracle pl/sql 中,显式游标和隐式游标本质不同:前者是用户定义的命名查询,后者由 sql 引擎自动管理。漏写 cursor 关键字会导致编译报错 pls-00103: encountered the symbol "is" 或类似语法错误。
常见错误是把显式游标当成变量声明来写,比如:DECLARE c1 SYS_REFCURSOR; —— 这其实是声明了一个游标变量(ref cursor),不是显式游标;又或者写成 DECLARE c1 IS SELECT ... —— 缺少 CURSOR,语法不合法。
-
CURSOR c1 IS SELECT empno, ename FROM emp WHERE deptno = 10;✅ 正确声明 -
DECLARE c1 SYS_REFCURSOR;→ 后续需用OPEN c1 FOR ...,属于动态游标,不是本题所指的显式游标 - 游标名不能重复,也不能与已存在的变量同名,否则报
PLS-00320
OPEN/FETCH/CLOSE 必须成对出现,且 FETCH 前必须 OPEN
显式游标不是“打开即取完”,它是一次性定位到结果集起点,每次 FETCH 移动一行。没 OPEN 就 FETCH,会触发运行时异常 ORA-01001: invalid cursor;没 CLOSE 虽不报错,但长期运行可能耗尽游标句柄(尤其在包中反复调用时)。
- 必须先
OPEN c1;,再FETCH c1 INTO v_empno, v_ename; -
FETCH返回%NOTFOUND表示已无数据,这是控制循环的关键,不是靠ROWCOUNT -
CLOSE c1;应该放在所有FETCH结束后,包括异常分支里(建议用EXCEPTION+CLOSE配合) - 若在循环中反复
OPEN/CLOSE同一个游标,性能差;应避免在循环内重复打开
游标参数化时,OPEN 传参顺序和类型必须严格匹配声明
带参数的显式游标(如 CURSOR c1(p_deptno NUMBER) IS SELECT ... WHERE deptno = p_deptno;)看起来像函数,但调用时没有类型推导,全靠位置和声明一致。错位或类型不兼容不会编译报错,但运行时可能查不到数据或隐式转换失败。
-
OPEN c1(10);✅ 匹配p_deptno NUMBER -
OPEN c1('10');→ 字符串转数字虽常能成功,但一旦字段是VARCHAR2且含非数字字符,就会出错 - 多个参数时顺序不能颠倒,也没有命名参数语法(不像过程调用支持
name => value) - 参数只能是 IN 模式,不能被赋值,也不支持默认值
别在 FETCH 后直接用 %ROWCOUNT 判断是否取到数据
%ROWCOUNT 返回的是当前游标已成功 FETCH 的行数,首次 FETCH 前为 0,取到第一行后变成 1,但它无法区分“刚取到第 1 行”和“已取完所有行、最后一次 FETCH 失败”。真正可靠的结束判断是 %NOTFOUND。
- 错误写法:
IF c1%ROWCOUNT = 0 THEN ...—— 即使游标已打开,只要还没 FETCH,就为 0,但这不代表没数据 - 正确写法:
FETCH c1 INTO ...; EXIT WHEN c1%NOTFOUND;是标准循环退出条件 -
%FOUND和%NOTFOUND只有在FETCH执行后才有效,读取前是未定义状态 - 注意:如果游标结果集为空,第一次
FETCH就会让%NOTFOUND为TRUE,不会抛异常
实际写的时候,最容易被忽略的是异常路径里的 CLOSE 和参数类型隐式转换——看着执行成功,换一套数据就崩。










