尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

ORA-01007 变量不在选择列表?TaoToken 通道下 Codex 这样对照

ORA-01007 变量不在选择列表?TaoToken 通道下 Codex 这样对照 当你在 SQL*Plus 里执行匿名块fetch c_out into row_record突然报出ORA-01007: 变量不在选择列表中大多数时候不是游标没写好而是游标返回的列数和接收列数对不上。这篇文章从 Oracle 存储过程返回sys_refcursor的场景出发带你用 Codex 做一次静态对照同时把 Codex 的 API 通道切到 TaoToken。先打开 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentora01007_codex_top 创建一把 API Key后面配置 Codex 时要用。读完你会获得两样东西一是 ORA-01007 的排查清单二是 Codex 走 TaoToken 统一接入口的完整配置。这样以后再遇到游标列对不齐不用在多个控制台之间翻找 Key。1. ORA-01007 是怎么冒出来的proc_A 游标列与 row_record 对不上1.1 先看 proc_A 和匿名块的原型原文里有一个典型的存储过程proc_A它通过动态 SQL 打开一个sys_refcursor把结果集返回给调用方。我们把代码缩略如下变量名和拼接方式做了调整逻辑与原文一致create or replace procedure proc_a( p_id in number, p_cur out sys_refcursor ) as l_sql clob; begin l_sql : select 总额, 自付, 自费 from 费用表 where id || p_id; open p_cur for l_sql; end;调用方写了一个匿名块先定义一个 record 类型再声明一个sys_refcursor变量然后调用proc_a并fetch游标内容到 record 变量里declare type type_record is record ( 总额 费用表.总额%type, 自付 费用表.自付%type, 自费 费用表.自费%type ); row_record type_record; c_out sys_refcursor; begin proc_a(123, c_out); fetch c_out into row_record; dbms_output.put_line(row_record.总额); end; /如果一切正常这个匿名块会输出总额字段。但很多人第一次跑的时候会在fetch那一行遇到ORA-01007: variable not in select list也就是标题里的“变量不在选择列表”。1.2 根因分析FETCH INTO 与选择列表的列数必须一致ORA-01007的官方含义是variable not in select list翻译成中文是“变量不在选择列表中”。这句话比较容易误导人它不是告诉你游标里的某个列名不存在而是说FETCH INTO后面的接收变量的个数和游标SELECT出来的列数没有对齐。Oracle 的FETCH ... INTO要求两侧严格匹配游标SELECT返回了 N 列INTO就需要接收 N 个变量或一个包含 N 个字段的 record 变量。如果游标返回 3 列但 record 只有 2 个字段或者游标实际返回 4 列而 record 只有 3 个字段都会报ORA-01007。反过来如果INTO的变量多于游标列数则报另一个错ORA-00947: not enough values。所以第一步不是去改游标而是数清楚两边到底各有几列。原文中提到“游标返回 3 列检索数据时的数据列不止 3 列多于 3 列”说的就是这种情况存储过程中动态 SQL 拼出来的游标实际返回的列数可能比调用方定义的 record 字段多。比如后来在费用表里加了字段或者proc_a内部按条件拼接了不同的 SELECT 分支都可能导致列数漂移。2. 用 Codex 做静态对照把 PL/SQL 扔给 AI 之前先理清四个检查项2.1 四个检查项在把代码交给 Codex 之前你自己心里要有数。排查ORA-01007时按下面的顺序检查列数是否相等直接数select 总额, 自付, 自费是 3 列record 定义里也是 3 个字段那这个方向暂时没问题。动态 SQL 是否走分支proc_a里如果用了if或case拼接不同的 SELECT 语句那么不同入参可能返回不同列数。你需要把p_id的实际值代入看走了哪个分支。游标变量是否写错声明的是c_out调用时却写成c_coutOracle 会先报PLS-00201但如果你用了同义变量也可能让游标指向错误的结果集。SELECT 是否用了*如果动态 SQL 是select * from 费用表那么表结构一变游标列数就跟着变调用方的 record 绝不会自动同步。这四个检查项Codex 可以帮你更快地完成。你只需要把proc_a的定义和匿名块完整贴给它它就能做静态对比指出两边字段数量的差异。2.2 让 Codex 生成游标列数诊断脚本如果代码里看不出来那就让数据库告诉你游标到底返回了几列。Oracle 提供的DBMS_SQL包可以把sys_refcursor转换成游标编号然后描述出它的列数。下面这段 PL/SQL 可以作为诊断脚本由你在 SQL*Plus 或本地数据库里执行不要把它写进生产存储过程declare c sys_refcursor; cur integer; col_cnt integer; cols dbms_sql.desc_tab; begin proc_a(123, c); cur : dbms_sql.to_cursor_number(c); dbms_sql.describe_columns(cur, col_cnt, cols); dbms_output.put_line(游标返回列数: || col_cnt); for i in 1..col_cnt loop dbms_output.put_line(第 || i || 列: || cols(i).col_name); end loop; dbms_sql.close_cursor(cur); end; /执行后会打印出游标返回的每一列名称和总列数。把它和type_record的字段定义做对比ORA-01007的根源就清楚了。这个脚本完全可以交给 Codex 生成你只需要把报错信息和存储过程定义贴给它告诉它“请帮我写一个诊断脚本输出游标列数”。3. TaoToken 通道下接入 Codexconfig.toml 的正确写法3.1 在 TaoToken 创建 Key要用 Codex 帮你做上面的对照先得解决 Key 的问题。打开 TaoToken 注册进入控制台创建 API Key。创建后你会得到一串 Key在后面的配置里统一用YOUR_API_KEY占位。TaoToken 是一个统一 API 通道它提供模型广场和用量控制台你可以在一处完成选模型、看额度、查调用记录而不是在好几个模型厂商的页面里来回切换。3.2 配置 ~/.codex/config.toml 和 Base URLCodex 命令行的配置文件位于~/.codex/config.toml。如果你还没有这个文件可以手动创建。把下面的内容填入注意模型 ID 要以 TaoToken 模型广场当时列出的为准不要照抄别人的model 你的模型ID model_provider taotoken [model_providers.taotoken] name TaoToken base_url https://taotoken.net/api env_key TAOTOKEN_API_KEY然后在 shell 环境里设置 API Keyexport TAOTOKEN_API_KEYYOUR_API_KEY这里最关键的一点Base URL 填的是https://taotoken.net/api末尾不要加/v1。很多从 OpenAI 官方配置切过来的人会习惯性写成https://taotoken.net/api/v1这个结尾是不对的。TaoToken 的接口地址本身就包含了兼容层路径再加/v1会 404。另外https://taotoken.net/api是给工具填的接口地址而注册、创建 Key、看用量都去 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentora01007_codex_key 这个落地页操作不要混用。3.3 为什么用 TaoToken 而不是分别维护多个 Key排障过程中最烦的事情不是 SQL 本身而是手里有好几个模型的 Key每个还剩多少额度不记得。TaoToken 把多个模型放到同一个通道下你只需要一把 Key就能在 Codex 里调用不同模型。官方额度不够时你不用立刻去开新账号而是先在 TaoToken 的模型广场找可用的模型把 ID 填进config.toml就行。对于“游标列数对不上”这类需要来回试的问题这种切换方式能省不少时间。4. 实战排障把报错和 proc_A 定义一起交给 Codex4.1 一个有效的提问模板Codex 不是直接连你的数据库执行 SQL它只能读你贴过去的代码和报错然后给出分析和修改建议。所以提问时要把上下文给全。推荐用下面这个模板第一段贴proc_a的完整定义。第二段贴匿名块里type_record的定义和fetch语句。第三段贴报错全文ORA-01007: variable not in select list。第四段问一句“请帮我检查游标返回列数与 record 字段数是否一致如果一致再帮我生成一个 DBMS_SQL 诊断脚本。”Codex 会先做静态对照告诉你游标 SELECT 有 3 列record 有 3 列看起来匹配然后它会提醒你检查动态 SQL 是否因为p_id的不同而走了别的分支。如果你在 1.1 的示例代码之外实际存储过程里还拼接了其他字段Codex 会直接指出多出来的列名和位置。4.2 验证修复结果与同类 ORA-00932 的区分假设最终定位到游标实际返回了 4 列而row_record只有 3 个字段修复方式有两种要么在 record 类型里补上第 4 个字段要么修改proc_a的 SELECT 列表让它固定返回 3 列。改完之后重新在本地执行匿名块观察dbms_output是否正常输出并且不报错。这里还要注意区分ORA-01007和ORA-00932。后者报的是“数据类型不一致”是游标返回列的数据类型和接收变量的数据类型不匹配。比如游标返回的是NUMBERrecord 字段却定义成VARCHAR2就会触发ORA-00932。排查时让 Codex 对照费用表里的列类型和%type定义它会帮你标出类型不一致的位置。完成这次排障后如果你想确认刚才和 Codex 的对话确实消耗了 TaoToken 的额度可以回控制台看调用记录。登录 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentora01007_codex_verify 在用量页面能看到本次请求的模型、时间和 token 消耗。这个动作相当于给排障画一个句号。5. 把排障经验沉淀到 proc_A 里避免下次再踩5.1 在存储过程头部写清游标契约存储过程返回sys_refcursor本质是给调用方一个“结果集契约”。契约里最重要的信息就是列名、列顺序、列类型。你可以把这段契约写到存储过程头部注释里这样下次任何人调用都知道游标长什么样。Codex 可以帮你把注释生成出来比如-- 返回游标列定义契约 -- 1. 总额 NUMBER -- 2. 自付 NUMBER -- 3. 自费 NUMBER create or replace procedure proc_a(...)如果以后表结构变了打开注释就能知道游标列是否要同步修改。5.2 ORA-01007 快速检查清单把这次排障经验压缩成一份清单放到你的笔记里确认游标SELECT写法是否有动态拼接分支。对照 record 定义数清两边列数。用DBMS_SQL.DESCRIBE_COLUMNS打印实际游标列。修完后重新fetch看是否还有别的 ORA 报错。检查游标变量名、参数名是否拼写一致。以后只要看到ORA-01007照着这个清单走一遍五分钟内就能定位。6. 这次排障用掉的额度去 TaoToken 控制台对一下配置好 Codex 并完成上面的排障之后建议顺手做一次验证在 TaoToken 模型对话 里用同一把 Key 发一条消息确认 API 通道是通的。如果你准备长期用 Codex 写代码、查 PL/SQL 报错可以看看 Coding Plan 是否更适合你的调用量。新增 Key 和管理入口在 控制台 API Keys。Codex 接入时如果对 Base URL 或环境变量的写法不确定参考 Claude Code 接入文档 里的地址拼接规则Claude Code 与 Codex 在 Base URL 的处理上是同一套逻辑。下次再遇到类似的游标列数问题不要急着一条条数。先让 Codex 读代码再用DBMS_SQL验证最后把结论写回存储过程注释。整个过程只靠一把YOUR_API_KEY就能跑通这就是统一 API 通道带来的省事。
返回列表