首页/新闻资讯/正文详情

Oracle cursor(游标)总结:从显式游标到REF游标的配置与验证

发布时间:2026/9/26 14:16:57 来源:云帆数科 栏目:资讯中心
Oracle cursor(游标)总结:从显式游标到REF游标的配置与验证
1. 为什么你写的游标总在%NOTFOUND上翻车Oracle 的 cursor游标本质上是一个指向查询结果集的指针你可以把它想成「数据库帮你把 SELECT 结果先缓存成一个可逐行读取的容器」。它真正解决的问题是当结果集有几千上万行、又需要在 PL/SQL 里逐行做业务判断时一次性SELECT INTO会直接抛TOO_MANY_ROWS而游标能让你一行一行地取、一行一行地处理。游标分三类隐式游标DML 自动带的 SQL 游标、显式游标静态编译期就绑定 SQL、REF 游标动态运行时才绑定 SQL。前两者属于静态游标REF 游标属于动态游标这个区别决定了你能不能把「查什么表」当成参数传进存储过程。这篇面向正在写存储过程、批处理脚本的数据库开发者交付的是可以直接复制进 SQL*Plus 或 SQL Developer 跑通的游标骨架包括声明、打开、取值、关闭全流程以及%FOUND、%NOTFOUND、%ROWCOUNT三个属性的验证动作。如果你之前遇到过「循环多输出一行」「exit when位置写错导致死循环」「REF 游标在包里声明报错」下面的排障部分基本能对上号。2. 前置准备环境与 TaoToken 接入在动手写游标之前先把执行环境理清楚。游标代码本身不依赖任何外部服务但如果你想让 AI 辅助生成或审查游标逻辑可以走 TaoToken 的模型对话入口把 PL/SQL 片段贴进去让它帮你找%NOTFOUND位置问题。TaoToken 官网地址是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 入口是 https://taotoken.net/api 。如果你打算在脚本里批量调用模型来审查游标代码需要先去控制台创建密钥控制台https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewriteAPI Keys 管理https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite数据库侧的准备很简单一个能连上的 Oracle 实例11g 及以上都行一张有数据的测试表。下面统一用经典的emp表举例字段包括empno、ename、sal。执行前记得打开输出SET SERVEROUTPUT ON;注意DBMS_OUTPUT.PUT_LINE只有在SERVEROUTPUT打开时才会显示很多人写完游标看不到输出第一反应是代码错了其实是这个开关没开。3. 可复制配置三类游标的完整骨架3.1 隐式游标DML 自动管理属性挂在 SQL 上隐式游标不需要你声明任何UPDATE、DELETE、INSERT执行时 Oracle 自动创建属性通过SQL%属性访问。它的%ISOPEN永远是FALSE因为 Oracle 在执行完 DML 后立刻关闭了它。DECLARE v_empno emp.empno%TYPE : 7000; BEGIN UPDATE emp SET ename fxe WHERE empno v_empno; IF SQL%FOUND THEN DBMS_OUTPUT.PUT_LINE(SQL%ROWCOUNT || 行被更新); END IF; IF SQL%NOTFOUND THEN DBMS_OUTPUT.PUT_LINE(雇员编号 || v_empno || 不存在); END IF; END; /这里的关键点是SQL%ROWCOUNT必须在 DML 之后、下一条 DML 之前读取否则会被覆盖。我见过有人在IF里先调了一次SQL%ROWCOUNT再在ELSE分支里又调一次结果第二次拿到的是 0因为中间夹了别的语句。3.2 显式游标声明、打开、取值、关闭四步走显式游标是静态的声明时就绑定了 SQL。标准四步DECLARE CURSOR emp_cur IS SELECT * FROM emp; empRecord emp%ROWTYPE; BEGIN OPEN emp_cur; LOOP FETCH emp_cur INTO empRecord; EXIT WHEN emp_cur%NOTFOUND; DBMS_OUTPUT.PUT_LINE(empRecord.ename); END LOOP; CLOSE emp_cur; END; /EXIT WHEN必须放在FETCH之后、业务逻辑之前。原因FETCH取不到行时%NOTFOUND才变TRUE如果你把EXIT写在FETCH前面第一次循环时%NOTFOUND还是初始的FALSE会多处理一行空数据。带参数的显式游标把过滤条件参数化DECLARE CURSOR emp_cur(dest VARCHAR2) IS SELECT * FROM emp WHERE empno dest; empRecord emp%ROWTYPE; BEGIN OPEN emp_cur(7369); LOOP FETCH emp_cur INTO empRecord; EXIT WHEN emp_cur%NOTFOUND; DBMS_OUTPUT.PUT_LINE(empRecord.ename); END LOOP; CLOSE emp_cur; END; /3.3 游标更新FOR UPDATE配合WHERE CURRENT OF当你要在遍历过程中更新「当前行」声明游标时必须加FOR UPDATE更新时用WHERE CURRENT OF 游标名这样 Oracle 会锁定活动集里的行避免并发修改。DECLARE old_sal NUMBER(4); emp_name VARCHAR2(20); CURSOR emp_cur IS SELECT ename, sal FROM emp WHERE sal 1000 FOR UPDATE OF sal; BEGIN OPEN emp_cur; LOOP FETCH emp_cur INTO emp_name, old_sal; EXIT WHEN emp_cur%NOTFOUND; UPDATE emp SET sal 1.1 * old_sal WHERE CURRENT OF emp_cur; DBMS_OUTPUT.PUT_LINE(emp_name || 更新成功); END LOOP; CLOSE emp_cur; END; /3.4 循环游标省掉 OPEN/FETCH/CLOSE 的简化写法如果你只是要遍历全部记录、不需要手动控制打开关闭用FOR ... IN循环游标最省事Oracle 自动完成打开、取值、关闭DECLARE CURSOR emp_cur IS SELECT empno, ename, sal FROM emp; BEGIN FOR empRecord IN emp_cur LOOP DBMS_OUTPUT.PUT_LINE(empRecord.empno || || empRecord.ename || || empRecord.sal); END LOOP; END; /注意empRecord是隐式声明的记录变量不需要你提前定义也不能在循环外引用。3.5 REF 游标运行时绑定 SQL 的动态游标REF 游标分两步先声明类型再声明变量。强类型带RETURN弱类型不带。DECLARE TYPE emp_cur IS REF CURSOR RETURN emp%ROWTYPE; -- 强类型 empObj emp_cur; empRecord emp%ROWTYPE; BEGIN OPEN empObj FOR SELECT * FROM emp; LOOP FETCH empObj INTO empRecord; EXIT WHEN empObj%NOTFOUND; DBMS_OUTPUT.PUT_LINE(empRecord.ename); END LOOP; CLOSE empObj; END; /弱类型就是把RETURN emp%ROWTYPE去掉这样同一个变量可以OPEN FOR不同的 SELECT。REF 游标最大的价值是可以作为存储过程的OUT参数把结果集返回给调用方这是静态游标做不到的。4. 验证请求跑一遍看属性对不对把下面这段放进 SQL Developer 执行验证%ROWCOUNT和%NOTFOUND的行为DECLARE CURSOR emp_cur IS SELECT ename FROM emp WHERE sal 5000; v_name emp.ename%TYPE; v_count NUMBER : 0; BEGIN OPEN emp_cur; LOOP FETCH emp_cur INTO v_name; EXIT WHEN emp_cur%NOTFOUND; v_count : v_count 1; DBMS_OUTPUT.PUT_LINE(第 || v_count || 行: || v_name); END LOOP; DBMS_OUTPUT.PUT_LINE(游标属性 %ROWCOUNT || emp_cur%ROWCOUNT); CLOSE emp_cur; END; /预期结果每行输出带序号最后一行打印%ROWCOUNT等于实际取到的行数。如果%ROWCOUNT比实际行数多 1说明你的EXIT WHEN位置有问题——FETCH失败那次也会让%ROWCOUNT加 1但%NOTFOUND为TRUE时你已经退出了所以正常情况不会多。再验证 REF 游标作为过程参数CREATE OR REPLACE PROCEDURE get_emp_by_dept( p_deptno IN NUMBER, p_cursor OUT SYS_REFCURSOR ) AS BEGIN OPEN p_cursor FOR SELECT empno, ename FROM emp WHERE deptno p_deptno; END; /调用时用SYS_REFCURSOR接收这是 Oracle 预定义的弱类型 REF 游标省去自己声明类型。5. 本篇常见错排查报错ORA-01001: invalid cursor通常是OPEN之前就FETCH或者CLOSE之后又FETCH。检查你的OPEN/CLOSE是否成对循环里有没有提前CLOSE。报错ORA-06550: PLS-00201: identifier SYS_REFCURSOR must be declared客户端版本太老或者你在匿名块里用了但没权限。换成自己声明的TYPE ... IS REF CURSOR即可。循环多输出一行空值EXIT WHEN写在了FETCH前面。记住顺序永远是FETCH→EXIT WHEN %NOTFOUND→ 业务逻辑。%ROWCOUNT拿到 0在 DML 之后插了别的语句才读属性。隐式游标的属性必须紧跟 DML 读取。REF 游标在包PACKAGE里声明报错这是 Oracle 的限制游标变量不能在包规范里声明只能在过程或匿名块里声明。如果你需要跨过程传递结果集用SYS_REFCURSOR作为参数类型。FOR UPDATE和 REF 游标一起用报错FOR UPDATE子句不能与游标变量一起使用这是 REF 游标的硬限制。需要锁行的话改用静态显式游标。WHERE CURRENT OF报ORA-01410: invalid ROWID游标声明时没加FOR UPDATE或者活动集被其他会话改了。确认声明语句里有FOR UPDATE OF 列名。6. 接下来怎么用如果你只是偶尔写几个游标上面这些骨架复制改改就够了。但如果你在维护几十个存储过程、需要批量审查游标逻辑比如统一检查EXIT WHEN位置、%ROWCOUNT读取时机手动看效率很低。这种场景可以走 TaoToken 的 Coding Plan把 PL/SQL 文件批量丢进去做静态审查https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite如果你更习惯在对话里逐段调试直接用模型对话入口贴代码问https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewrite接入细节和参数说明在文档里https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite最后留一个我踩过的坑写循环游标时不要在里面做COMMITFOR ... IN循环游标底层用的是隐式打开的快照中途COMMIT可能导致ORA-01555: snapshot too old尤其是大表遍历时。要提交就等循环结束后统一提交。

相关推荐

Python自动收发邮件实战:从SMTP/IMAP到定时调度完整指南
Python自动收发邮件实战:从SMTP/IMAP到定时调度完整指南

你有没有经历过这样的早晨:手机弹出一堆邮件提醒,真正重要的其实就一两封,剩下的全是系统通知、自动抄送和无关紧要的周报。我是被某次值班夜的告警邮件折腾怕了,才下决心把所有和邮件相关的重复劳动全交给脚本。这篇文章不绕弯子… · 2026/9/26 14:16:49

MiniMax-H3 INT4量化部署实战:16GB显存跑通关键路径
MiniMax-H3 INT4量化部署实战:16GB显存跑通关键路径

1. 这不是“跑个模型”那么简单:为什么16GB显存成了MiniMax-H3本地部署的生死线你搜“MiniMax-H3 本地部署”,页面刷出来全是“显存不足”“OOM Killed”“CUDA out of memory”的报错截图,再往下翻,有人晒出T4 16GB卡跑通的截图&… · 2026/9/26 14:16:49

水下长基线定位全解析:从测距原理到工程避坑指南
水下长基线定位全解析:从测距原理到工程避坑指南

简介:面向海洋科学研究、水下导航、深海救援等需要高精度水声定位的场景,这份MATLAB仿真代码包聚焦长基线定位系统的核心原理与算法实现,适合水声工程、海洋技术专业的学生、科研人员及相关工程师快速上手。压缩包共3个文件,均为.… · 2026/9/26 14:16:49

PowerShell执行策略拦下npm.ps1?一文看懂报错根因与OpenClaw安装破解法
PowerShell执行策略拦下npm.ps1?一文看懂报错根因与OpenClaw安装破解法

如果你在Windows上安装OpenClaw,或者任何依赖npm的Node项目,很大概率会在终端里撞见这么一堵墙:npm : 无法加载文件 D:\Program Files\nodejs\npm.ps1,因为在此系统上禁止运行脚本。我第一次遇到这个报错时也愣了一下,… · 2026/9/26 14:52:05

苹果产品自助网址全攻略:保修查询、固件下载与验机避坑指南
苹果产品自助网址全攻略:保修查询、固件下载与验机避坑指南

1. 苹果产品自助网址到底是个什么东西第一次听到“苹果产品自助网址”这个词,很多人脑子里冒出来的画面可能是某个神秘的链接,点进去就能查保修、查序列号、预约维修、下载固件。实际上,这个说法在苹果用户圈子里流传已久,它并不是… · 2026/9/26 14:52:05

基于大模型的自动代码评审工具open-code-review实践
基于大模型的自动代码评审工具open-code-review实践

1. 我为什么会做 open-code-review 这个项目 先交代一下背景。我所在的团队大概从两年前开始做微服务拆分,代码仓库从个位数涨到了三十多个,每次合并请求的评审压力肉眼可见地增大。不是不想认真 review,是真的看不过来——一个后端服务改动动… · 2026/9/26 14:52:05

网页禁止复制?三步解除CSS/JS封锁,合法恢复文本操作权
网页禁止复制?三步解除CSS/JS封锁,合法恢复文本操作权

1. 这不是“破解”,而是对网页交互逻辑的正当理解与合理应对“大学生急救手册 | 解决作业禁止复制粘贴”——这个标题乍看像某种技术黑产指南,实则折射出一个被长期忽视的现实:大量高校在线教学平台、题库系统、考试系统在未提供合理替代方案… · 2026/9/26 14:51:58

用Claude Code拆解改造视频:Hypit工作流完整实操指南
用Claude Code拆解改造视频:Hypit工作流完整实操指南

直接讲个场景:你刷到一条爆款视频,无论是口播科普、产品测评还是探店日常,心里蹦出的第一个念头多半是“我也想做一条自己的版本”。但真上手就发现,逐帧模仿拍摄根本不现实,人工拆解脚本、记录分镜、复刻剪辑节奏&… · 2026/9/26 14:51:58

OpenCode 添加 Skills 完全指南:安装、编写与实战排查
OpenCode 添加 Skills 完全指南:安装、编写与实战排查

最近一年我把 Cursor、Windsurf、VS Code Copilot、Trae、Claude Code、Codex 这些 AI 编程助手轮着用了个遍,最后留在终端里的反而是 OpenCode。原因很简单:它不搞花里胡哨的界面,直接在命令行里干活,多模型自由切换,… · 2026/9/26 14:51:58

数据库课后习题答案别硬背:当测试用例集刷,效率翻倍
数据库课后习题答案别硬背:当测试用例集刷,效率翻倍

简介:万常选版《数据库原理与设计》课后习题答案资源,覆盖第2至6章及第9章,适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件,含3个doc参考答案、2个sql示例脚本、… · 2026/9/26 0:00:21

OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置
OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 0:00:40

向下兼容与向上兼容:接口设计中的兼容性策略与工程实践
向下兼容与向上兼容:接口设计中的兼容性策略与工程实践

一次版本升级事故,是很多团队绕不过去的坎。线上环境里,服务端明明已经上线了新版接口,老的移动端还在照着旧文档传参数。请求一到网关,校验直接拒绝,用户操作失败,客服群炸了锅,开发群里开始互… · 2026/9/26 0:00:46

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码