ORACLE 经验两则:Sys_Refcursor 与外部表 SKIP 的配置骨架
1. 为什么这两个 ORACLE 老问题总在项目里反复出现做 ORACLE 存储过程开发或者数据加载的 DBA大概率都遇到过两个绕不开的场景一个是要在存储过程里把一段查询结果直接吐给上层应用另一个是把外部文本文件挂进数据库当表查。前者绕不开Sys_Refcursor后者绕不开外部表的SKIP子句。Sys_Refcursor是 ORACLE 9i 之后引入的弱类型游标好处是不用再像 9i 之前那样先TYPE ... IS REF CURSOR定义一个自定义类型直接拿它当OUT参数就能把结果集返回给调用方。听起来简单但实际写的时候参数顺序、OPEN ... FOR的写法、调用端怎么接每一步都有坑。外部表这边ORGANIZATION EXTERNAL配合oracle_loader能把服务器上的文本文件当普通表查。真正让人头疼的是文件头很多批处理文件第一行是标题或者总控行直接加载会把脏数据带进来这时候就得靠SKIP 1跳过去。再加上 DOS 和 UNIX 换行符不一样records delimited by newline和records delimited by 0x0A用错了整张表可能一行都读不出来。这篇就把这两块的可复制骨架拆开讲清楚配置直接拿去改字段名就能用。排查阶段如果想让 AI 工具帮你快速定位语法或者参数问题可以用 TaoToken 统一一个 Key 走 API 通道省得在多个工具之间来回切。2. TaoToken 前置把 AI 排查通道先接上在写存储过程和外部表的过程中报错信息往往比较短比如ORA-00942、ORA-29913这种光看编号不好判断是权限、路径还是语法问题。这时候让 AI 帮你把报错和上下文一起分析会快很多。TaoToken 在这里的作用是提供一个统一的 API 入口你不用为每个 AI 工具单独配一套 Key。官网入口是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 地址是 https://taotoken.net/api 注意 API 这个地址不带 UTM 参数。具体操作上先去控制台创建一个 Key地址是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 然后在 API Keys 页面拿到密钥地址是 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。拿到之后你可以在本地脚本或者 AI 编码工具里把 base_url 指向https://taotoken.net/api模型名按文档里给的填。如果你只是想快速验证某个 ORACLE 语法或者让模型解释一段报错直接用模型对话页面就行https://taotoken.net/model-chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewrite 。要是你长期在写 PL/SQL、做数据加载脚本想让 AI 持续参与编码可以看 Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里面写了不同语言怎么调。注意TaoToken 只是帮你统一 AI 工具的调用通道不替代数据库客户端也不碰你的生产库连接。所有 SQL 还是在你自己的 ORACLE 环境里执行。3. Sys_Refcursor 存储过程可复制配置3.1 最小可跑的存储过程骨架先看一个完整的存储过程入参是业务日期范围和两个业务代码出参就是一个Sys_Refcursor。字段名我用了中文别名方便你对照结果。CREATE OR REPLACE PROCEDURE Zkquery ( p_Jyjh IN VARCHAR2, p_Wtdm IN VARCHAR2, p_Begindate IN DATE, p_Enddate IN DATE, Cur OUT SYS_REFCURSOR ) AS BEGIN OPEN Cur FOR SELECT Fpclh AS 批处理号, Fyyf AS 费用月份, Zhs AS 托收户数, Zje / 100 AS 托收金额, Cghs AS 成功户数, Cgje AS 成功金额, CASE WHEN Bz 0 THEN 未作返回 ELSE 已做返回 END AS 返回标志, Scph AS 上传批号, Schs AS 上传户数, Scje / 100 AS 上传金额, Zxrq AS 执行日期, Ctpc AS 出托批次, Sntfile AS 扣费文件, Rtnfile AS 返回盘文件 FROM t_Zkzl WHERE Wtdm p_Wtdm AND Jyjh p_Jyjh AND Zxrq BETWEEN p_Begindate AND p_Enddate; END Zkquery; /这里有几个点值得说。第一SYS_REFCURSOR是 ORACLE 预定义的弱类型游标不需要你自己TYPE。第二OPEN Cur FOR后面直接跟SELECT游标和查询是绑定的。第三OUT参数不需要初始化过程内部OPEN之后调用方就能取到结果。3.2 调用端怎么接这个游标在 SQL*Plus 或者 SQL Developer 里可以这样调VARIABLE rc REFCURSOR; EXEC Zkquery(JY001, WD001, TO_DATE(2024-01-01,YYYY-MM-DD), TO_DATE(2024-01-31,YYYY-MM-DD), :rc); PRINT rc;在 Java 里用 JDBC 调的话注册Types.REF_CURSOR或者OracleTypes.CURSOR然后callableStatement.registerOutParameter(5, OracleTypes.CURSOR)执行完getObject(5)拿到ResultSet再遍历。在另一个存储过程里调用就声明一个SYS_REFCURSOR变量传进去DECLARE v_cur SYS_REFCURSOR; v_row t_Zkzl%ROWTYPE; BEGIN Zkquery(JY001, WD001, SYSDATE - 30, SYSDATE, v_cur); LOOP FETCH v_cur INTO v_row; EXIT WHEN v_cur%NOTFOUND; DBMS_OUTPUT.PUT_LINE(v_row.Fpclh); END LOOP; CLOSE v_cur; END; /3.3 参数对照表参数名方向类型说明p_JyjhINVARCHAR2交易计划号过滤条件p_WtdmINVARCHAR2委托代码过滤条件p_BegindateINDATE执行日期起始p_EnddateINDATE执行日期结束CurOUTSYS_REFCURSOR返回结果集游标提示SYS_REFCURSOR是弱类型字段结构由OPEN FOR的查询决定调用方不需要提前知道列定义但这也意味着编译期不会帮你检查列名拼写写的时候要仔细。4. 外部表 SKIP 跳行配置骨架4.1 DOS 格式文件的外部表DOS 格式换行是\r\n用records delimited by newline让 ORACLE 自己识别。SKIP 1跳过第一行标题。CREATE TABLE DXPK ( ZSXH VARCHAR2(20), HM VARCHAR2(20), A VARCHAR2(10), JFHM VARCHAR2(30), ZH VARCHAR2(20), RQ VARCHAR2(15), FYJE NUMBER, B VARCHAR2(10), C VARCHAR2(1), D VARCHAR2(1), PNXH VARCHAR2(10) ) ORGANIZATION EXTERNAL ( TYPE oracle_loader DEFAULT DIRECTORY pkdata ACCESS PARAMETERS ( records delimited by newline skip 1 nologfile nobadfile nodiscardfile fields terminated by | missing field values are null reject rows with all null fields ) LOCATION (Dxpk) ) PARALLEL 4 REJECT LIMIT UNLIMITED;4.2 UNIX 格式文件的外部表UNIX 换行是\n对应十六进制0x0A。这里skip 1的位置和 DOS 版本略有不同写在records delimited by 0x0A之后、fields terminated by之前。CREATE TABLE RTN ( XH VARCHAR2(8), YDM VARCHAR2(2), ZKBZ VARCHAR2(1), ZH VARCHAR2(19), KHJDM VARCHAR2(20), HM VARCHAR2(30), CKYE NUMBER, KYYE NUMBER, JYJE NUMBER, ZJSXF NUMBER, YWSXF NUMBER, YLSXF NUMBER ) ORGANIZATION EXTERNAL ( TYPE oracle_loader DEFAULT DIRECTORY pkdata ACCESS PARAMETERS ( records delimited by 0x0A nologfile nobadfile nodiscardfile skip 1 fields terminated by | missing field values are null reject rows with all null fields ) LOCATION (RTN) ) PARALLEL 4 REJECT LIMIT UNLIMITED;4.3 关键子句对照子句作用常见取值records delimited by指定行分隔符newline / 0x0Askip跳过文件开头行数1跳标题fields terminated by字段分隔符| / , / 0x09missing field values are null缺失字段置空固定写法reject rows with all null fields全空行丢弃固定写法nologfile / nobadfile / nodiscardfile不生成日志和坏文件按需REJECT LIMIT允许拒绝行数UNLIMITED / 数字注意DEFAULT DIRECTORY pkdata里的目录必须是数据库里已经创建的 DIRECTORY 对象而且 ORACLE 进程用户要有读权限。文件本身放在服务器文件系统上不是客户端。5. 验证请求与成功结果5.1 验证游标返回先确认存储过程编译通过SELECT object_name, status FROM user_objects WHERE object_type PROCEDURE AND object_name ZKQUERY;STATUS是VALID就说明编译没问题。然后在 SQL*Plus 里执行前面那段VARIABLE rc REFCURSOR的调用PRINT rc应该能看到查询结果集。如果是在应用端重点看ResultSet有没有数据、列名是不是和OPEN FOR里的别名一致。5.2 验证外部表加载外部表建好之后直接查SELECT COUNT(*) FROM DXPK; SELECT * FROM RTN WHERE ROWNUM 5;如果COUNT(*)返回 0先检查文件路径和文件名大小写。LOCATION (Dxpk)里的文件名要和服务器上实际文件名完全一致ORACLE 在部分平台上对大小写敏感。再查一下有没有被拒绝的行SELECT * FROM DXPK WHERE ROWNUM 10;如果字段错位多半是fields terminated by写错了或者文件里实际用的分隔符和配置不一致。可以用hexdump或者文本编辑器看下真实分隔符。5.3 用 AI 辅助排查把报错编号和你的建表语句一起丢给模型让它帮你比对参数。比如ORA-29913通常和外部表访问参数有关ORA-00942可能是表或视图不存在。通过 TaoToken 的模型对话页面可以直接问https://taotoken.net/model-chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewrite 。如果你在写一个批量加载脚本想让 AI 帮你生成多个外部表 DDL可以用 Coding Plan 持续对话https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。6. 本篇常见错排查6.1 Sys_Refcursor 相关报错 ORA-01001无效的游标。多半是游标没OPEN就FETCH或者已经CLOSE了还在用。检查OPEN Cur FOR是否执行到以及CLOSE的位置。调用端拿不到数据。先确认OPEN FOR里的WHERE条件是不是把数据全过滤掉了。可以先把条件去掉直接SELECT COUNT(*)看基表有没有数据。在存储过程里嵌套调用时游标被覆盖。如果外层过程也用了同名游标变量注意作用域。建议每个过程用独立的变量名。Java 端报SQLException: Invalid column type。检查registerOutParameter用的类型是不是OracleTypes.CURSOR不同 JDBC 驱动版本常量名可能不一样。6.2 外部表 SKIP 相关SKIP 没生效标题行还是进来了。确认skip的位置在ACCESS PARAMETERS括号内且拼写正确。DOS 和 UNIX 版本里skip和records delimited by的相对顺序可以调整但必须在fields terminated by之前。UNIX 文件用 newline 读出来是乱码或者只有一行。换成records delimited by 0x0A。反过来DOS 文件用0x0A可能每行末尾多一个\r导致最后一个字段带不可见字符。ORA-29913执行 ODCIEXTTABLEOPEN 调用时出错。通常是 DIRECTORY 对象不存在或者权限不够。用SELECT * FROM all_directories WHERE directory_name PKDATA;确认然后GRANT READ ON DIRECTORY pkdata TO 你的用户;。字段数对不上。外部表的列数要和文件里fields terminated by分隔后的字段数一致。少列会补 null多列会报错或者截断。建表前先用文本编辑器数一下每行有几个分隔符。REJECT LIMIT 设太小。如果文件里有少量脏数据REJECT LIMIT 0会导致查询直接失败。调试阶段先用UNLIMITED确认数据没问题再收紧。6.3 环境与权限外部表依赖服务器端文件系统客户端工具连过去只能看到表结构看不到文件。如果你在本地 SQL Developer 里建外部表文件必须放在数据库服务器上不是你的本机。DIRECTORY 对象的路径也是服务器路径。另外PARALLEL 4在数据量小的时候不一定更快反而可能因为并行度设置不当导致资源争用。单文件加载可以先去掉PARALLEL子句等确认功能正常再加。排查过程中如果报错信息太短可以把完整的 DDL、报错编号、文件前几行内容一起整理好通过 TaoToken 的 API 通道发给模型分析。接入方式参考文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite Key 在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 创建。这样一套流程走下来游标返回和外部表加载基本能一次跑通。

相关新闻

Claude 在得物 App 数仓的深度集成与效能演进:TaoToken 统一 Key 通道配置实战

Claude 在得物 App 数仓的深度集成与效能演进:TaoToken 统一 Key 通道配置实战

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

2026/9/25 13:13:40 阅读更多 →
WorkBuddy Enterprise 企业级 Agent 平台架构与 MCP 落地实践

WorkBuddy Enterprise 企业级 Agent 平台架构与 MCP 落地实践

1. 从「超级个体」到「超级团队」:这个平台到底在解决什么问题第一次看到「WorkBuddy Enterprise」这个名字,我脑子里蹦出来的第一个念头是:腾讯云终于把 CodeBuddy 那套东西往企业级方向推了。如果你最近半年一直在关注 Agent 开发这条线&am…

2026/9/25 13:13:40 阅读更多 →
Atlas 300V 24G实战:AI推理加速卡部署YOLO全流程

Atlas 300V 24G实战:AI推理加速卡部署YOLO全流程

很多人都为一个词搜过来:atlas。准确讲,搜到atlas又能和部署yolo扯上关系的,多半是盯上了华为Atlas 300V 24G这块卡。今天我不绕圈子,先说结论:Atlas 300V 24G确实是一块运算加速卡,但它更准确的定位&#…

2026/9/25 13:13:40 阅读更多 →

最新新闻

代码阅读工作流实战:用 TaoToken 统一 Key 打通文件搜索、符号跳转与提问策略

代码阅读工作流实战:用 TaoToken 统一 Key 打通文件搜索、符号跳转与提问策略

/* 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 16:40:44 阅读更多 →
5分钟读懂OpenManus配置:TaoToken统一Key接入Multi Agent实战

5分钟读懂OpenManus配置:TaoToken统一Key接入Multi Agent实战

/* 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 16:40:44 阅读更多 →
多酒店预订系统实战:数据隔离、房态同步与三端接入

多酒店预订系统实战:数据隔离、房态同步与三端接入

简介:这是一套面向酒店行业开发者与中小连锁酒店经营者的多酒店预订管理系统源码,覆盖APP、H5与小程序三端,可解决分店扩张、房态同步、会员营销与内部协同等实际业务问题。资源包共2582个文件,约80.13MB,以1428个PHP业…

2026/9/26 16:40:44 阅读更多 →
手势识别打地鼠实战:MediaPipe+OpenCV从摄像头到锤子的完整链路

手势识别打地鼠实战:MediaPipe+OpenCV从摄像头到锤子的完整链路

简介:这是一份面向人机交互课程学习者与OpenCV入门开发者的完整项目资料,围绕手势识别控制的打地鼠游戏展开,可用于课程设计、实验复现与交互方式对比研究。资源包共27个文件,约60.1MB,包含6个Python源码文件、4个XML配…

2026/9/26 16:40:44 阅读更多 →
AiPy 为 openclaw 穿上安全铠甲:skill 随便用也不翻车的 TrustTools 配置骨架

AiPy 为 openclaw 穿上安全铠甲:skill 随便用也不翻车的 TrustTools 配置骨架

/* 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 16:40:44 阅读更多 →
20家公司AI面试官吐血总结:3个月速成AI Agent开发,TaoToken统一Key接入Cline与CC Switch配置实战

20家公司AI面试官吐血总结:3个月速成AI Agent开发,TaoToken统一Key接入Cline与CC Switch配置实战

/* 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 16:39:44 阅读更多 →

日新闻

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

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

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

2026/9/26 0:00:25 阅读更多 →
学校官网模拟全流程实践:从页面布局到后端接口与部署

学校官网模拟全流程实践:从页面布局到后端接口与部署

如果你正在找一门 Web 大作业的题目,或者刚开始接触 Web 前端开发想做点能拿来展示的东西,“学校官网模拟”几乎是最稳的选择。题目看着简单,但要把导航、新闻列表、轮播 Banner、二级页面、后台数据都串起来,其实已经把前端布局、…

2026/9/26 0:00:25 阅读更多 →
超级玛丽游戏源码C++:从零搭建横版跳跃游戏工程

超级玛丽游戏源码C++:从零搭建横版跳跃游戏工程

简介:这是一份面向游戏开发初学者与C进阶学习者的超级玛丽(超级马里奥)游戏源码,基于C面向对象编程实现,适合想通过经典项目理解游戏主循环、角色类设计、地图关卡加载与物理碰撞检测的读者参考。压缩包共49个文件&…

2026/9/26 0:00:25 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/25 19:27:14 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/25 11:15:26 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/25 20:29:09 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/25 20:29:43 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/25 20:29:31 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/25 19:27:26 阅读更多 →