首页 > 数据库 >如何定义显式游标_CURSOR声明与OPEN/FETCH/CLOSE流程

如何定义显式游标_CURSOR声明与OPEN/FETCH/CLOSE流程

来源:互联网 2026-05-01 20:48:07

显式游标必须用 CURSOR 关键字声明,漏写会导致 PLS-00103 编译错误;其本质是用户定义的命名查询,需 OPEN/FETCH/CLOSE 成对使用,循环结束判断应依赖 %NOTFOUND 而非 %ROWCOUNT。 显式游标必须用 CURSOR 关键字声明,不能只写 DECLARE c1

显式游标必须用 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 ... 来动态关联 SQL,它属于另一种游标类型。
  • 另外,游标的名字可不能重复,也不能和已有的变量名冲突,否则会触发 PLS-00320 错误。

OPEN/FETCH/CLOSE 必须成对出现,且 FETCH 前必须 OPEN

显式游标的工作机制需要明确:它不是“一打开就自动把所有数据都给你”,而是通过 OPEN 操作定位到结果集的起点,然后每次执行 FETCH 才获取一行数据并向前移动。如果没执行 OPEN 就直接 FETCH,会引发运行时异常 ORA-01001: invalid cursor。至于 CLOSE,虽然忘记关闭不一定会立刻报错,但在长期运行的程序(尤其是包中反复调用)里,可能会逐渐耗尽数据库的游标资源,这可是个隐藏的性能杀手。

  • 标准流程必须是:先 OPEN c1;,然后才能 FETCH c1 INTO v_empno, v_ename;
  • 控制循环何时结束,关键要看 %NOTFOUND 属性,而不是 %ROWCOUNT
  • CLOSE c1; 应该放在所有数据获取完毕之后,稳妥起见,最好在异常处理分支中也加上关闭操作。
  • 还要注意,尽量避免在循环内部反复 OPENCLOSE 同一个游标,这种写法对性能很不友好。

游标参数化时,OPEN 传参顺序和类型必须严格匹配声明

给显式游标加上参数(比如 CURSOR c1(p_deptno NUMBER) IS SELECT ... WHERE deptno = p_deptno;)能让它更灵活,看起来有点像函数。但调用时可得小心:它没有智能的类型推导,完全依赖参数的位置和声明的类型严格匹配。如果顺序错了或者类型不兼容,编译阶段可能发现不了,但运行时要么查不到数据,要么就因隐式转换失败而报错。

  • OPEN c1(10); 这样传参,完美匹配 p_deptno NUMBER 的声明。
  • OPEN c1('10'); → 虽然字符串‘10’通常能隐式转成数字,但如果字段是 VARCHAR2 且包含了字母,那麻烦就来了。
  • 当有多个参数时,顺序绝对不能颠倒,而且它也不支持像过程调用那样使用命名参数(name => value)的语法。
  • 另外,游标参数只能是 IN 模式,不能在游标内部对其赋值,也不支持设置默认值。

别在 FETCH 后直接用 %ROWCOUNT 判断是否取到数据

这里有个细节很容易踩坑:%ROWCOUNT 属性返回的是自游标打开后,成功 FETCH 到的行数累计值。在第一次 FETCH 之前,它是0;成功取到第一行后,它就变成1。问题在于,你无法单纯通过这个数值来区分“刚刚成功取到第一行数据”和“已经取完所有数据、最后一次 FETCH 失败了”这两种情况。真正可靠、用于判断循环是否应该结束的“信号灯”,是 %NOTFOUND 属性。

  • 错误示范:IF c1%ROWCOUNT = 0 THEN ... —— 即使游标里确实有数据,但只要还没执行 FETCH%ROWCOUNT 就一直是0,这并不能证明结果集为空。
  • 正确姿势:FETCH c1 INTO ...; EXIT WHEN c1%NOTFOUND; 这才是控制循环退出的标准写法。
  • 记住,%FOUND%NOTFOUND 这两个属性,只有在执行了一次 FETCH 操作后才有效,在首次 FETCH 之前,它们的状态是未定义的。
  • 还有一个要点:如果游标的结果集本来就是空的,那么第一次 FETCH 就会立即将 %NOTFOUND 置为 TRUE,这个过程不会抛出任何异常。

在实际编码中,最容易疏忽的两点,恰恰是异常处理路径里忘记 CLOSE 游标,以及参数传递时的隐式类型转换——代码可能在某些测试数据下运行良好,一旦换一套数据,就可能瞬间崩溃,值得高度警惕。

侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述

热游推荐

更多
湘ICP备14008430号-1 湘公网安备 43070302000280号
All Rights Reserved
本站为非盈利网站,不接受任何广告。本站所有软件,都由网友
上传,如有侵犯你的版权,请发邮件给xiayx666@163.com
抵制不良色情、反动、暴力游戏。注意自我保护,谨防受骗上当。
适度游戏益脑,沉迷游戏伤身。合理安排时间,享受健康生活。