ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

@@fetch_status 总是 -1?让走 TaoToken 的 Codex 查游标循环

@@fetch_status 总是 -1?让走 TaoToken 的 Codex 查游标循环 fetch_status总为 -1用 TaoToken打开 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 创建 Key把 Codex 的 Base URL 填成 https://taotoken.net/api再让 Codex 检查你从 SQL Server 原文复制的游标。这个报错最容易被误判成“游标坏了”其实多数时候游标本身没坏坏的是FETCH NEXT与WHILE FETCH_STATUS 0的先后关系。你从原文那段DECLARE Employee_Cursor复制过来的脚本把FETCH NEXT放进了WHILE循环的第一行最后一行取完后状态位会翻成 -1循环要么多跑一次、要么提前退出。SQL Server 的fetch_status是全局变量任何一次FETCH都会改写它。它不看你的业务逻辑也不管你是不是在处理最后一行。所以排障时不要盯着 -1 本身而要盯“谁在什么时候执行了 FETCH”。下面按原文这段游标代码的路径把状态值、循环位置、Codex 配置和本地验证串起来。TaoToken 只负责给 Codex 提供 API Key 和 Base URL不直接连接 SQL Server也不替你在生产库跑任何 SQL。1.fetch_status频繁变 -1先看 FETCH NEXT 与 WHILE 的先后1.1 0、-1、-2 不是“成功、失败、结束”这么简单先把三个值摆清楚。fetch_status返回整数0 表示FETCH语句成功-1 表示FETCH语句失败或者这一行不在结果集中-2 表示被提取的行不存在。很多人把 -1 直接理解成“游标结束”这只说对了一半在FETCH NEXT取不到下一行时-1 确实是结束信号但它同时也是“本次 FETCH 失败”的信号。返回值含义常见触发0FETCH 成功取到了一行有效数据-1FETCH 失败或行不在结果集中最后一行之后继续 FETCH NEXT或游标未 OPEN-2被提取的行不存在行被删除、游标滚动到已不存在的行关键点是最后一行取完后下一次FETCH NEXT必然把状态改成 -1。这不是异常而是 SQL Server 在告诉你“没有下一行了”。真正要排查的是你在循环条件、循环体还是数据处理之后去读这个状态。读的时机不对就会把“没有下一行”误判成“当前行无效”或者让循环体在 -1 之后还执行一次。1.2 原文DECLARE Employee_Cursor为什么会让循环多跑或提前退出原文代码的结构是先OPEN然后第一次FETCH NEXT进入WHILE后又在BEGIN第一行立刻FETCH NEXT。这个顺序相当于你刚拿到第一行还没处理就先把第二行取回来了。第一行被跳过如果处理逻辑写在第二次FETCH后面最后一行取完后还会再取一次变量保留着上一轮的值于是最后一行被重复处理。若你在BEGIN里根据FETCH_STATUS做BREAK或CONTINUE又会因为读到的是下一次FETCH的状态而提前退出。把错误结构压缩成可读版本大致是这样DECLARE LastName nvarchar(20), FirstName nvarchar(20); DECLARE Employee_Cursor CURSOR LOCAL FAST_FORWARD FOR SELECT LastName, FirstName FROM Northwind.dbo.Employees ORDER BY LastName, FirstName; OPEN Employee_Cursor; FETCH NEXT FROM Employee_Cursor INTO LastName, FirstName; WHILE FETCH_STATUS 0 BEGIN FETCH NEXT FROM Employee_Cursor INTO LastName, FirstName; -- 处理当前行此时 LastName/FirstName 已经是下一行 PRINT CONCAT(LastName, N, , FirstName); END; CLOSE Employee_Cursor; DEALLOCATE Employee_Cursor;这段代码里WHILE条件读到的状态来自上一轮FETCH NEXT而BEGIN第一行的FETCH NEXT又把变量和状态同时推进了一格。结果就是第一行没被处理最后一行之后循环还可能多执行一次。你要查的不是fetch_status为什么是 -1而是FETCH NEXT为什么出现在处理逻辑之前。1.3 把 FETCH NEXT 放到循环末尾的修正写法修正原则只有一句话把FETCH NEXT放在循环体最后让WHILE条件在每一轮结束后再判断一次。循环前先取第一行BEGIN里先处理当前行最后再取下一行。最后一行处理完下一次取数返回 -1WHILE条件不成立循环自然结束不会多处理一次。DECLARE LastName nvarchar(20), FirstName nvarchar(20); DECLARE Employee_Cursor CURSOR LOCAL FAST_FORWARD FOR SELECT LastName, FirstName FROM Northwind.dbo.Employees ORDER BY LastName, FirstName; OPEN Employee_Cursor; FETCH NEXT FROM Employee_Cursor INTO LastName, FirstName; WHILE FETCH_STATUS 0 BEGIN -- 先处理当前行 PRINT CONCAT(LastName, N, , FirstName); -- 再取下一行循环条件下一轮再判断 FETCH NEXT FROM Employee_Cursor INTO LastName, FirstName; END; CLOSE Employee_Cursor; DEALLOCATE Employee_Cursor;这段脚本不需要 Codex 去连库执行。你把代码贴给 Codex让它对照 0、-1、-2 的含义检查FETCH NEXT的位置和循环终止条件即可。执行仍然由你在本地 SSMS 或 sqlcmd 里完成再把输出贴回对话。2. 让 Codex 检查游标之前先把 TaoToken 通道写进 ~/.codex/config.toml2.1 去 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 创建 API Key并确认模型 ID打开 TaoToken 注册并登录进控制台创建 API Key把它记成YOUR_API_KEY。模型 ID 不要凭记忆写直接看模型广场当时的列表哪个模型适合你的 Codex 工作流就选哪个。Codex 配置里出现的YOUR_MODEL_ID必须和 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 模型广场显示的一致不要自己拼日期后缀或猜一个不存在的名字。这一步只拿 Key 和模型 ID不涉及数据库账号也不需要把 SQL Server 的连接串交给任何工具。TaoToken 在这里的角色是统一 API 通道给 Codex 一把 Key、一个 Base URL让对话能正常发出去。SQL 能不能跑、游标改得对不对仍然由本地数据库和你的调试结果决定。2.2 Codex 的 config.tomlbase_url 用 https://taotoken.net/api不要带 /v1Codex 读的是~/.codex/config.tomlWindows 通常是%USERPROFILE%\.codex\config.toml。把自定义供应商写进去base_url填https://taotoken.net/api末尾不要加/v1。Key 通过环境变量注入配置文件里只写环境变量名不要直接写 Key。model YOUR_MODEL_ID model_provider taotoken [model_providers.taotoken] name TaoToken base_url https://taotoken.net/api env_key TAOTOKEN_API_KEY wire_api chatLinux 或 macOS 的终端里export TAOTOKEN_API_KEYYOUR_API_KEYWindows PowerShell 里$env:TAOTOKEN_API_KEYYOUR_API_KEY如果你的 Codex 版本要求wire_api responses按该版本官方说明改wire_api但base_url仍然是https://taotoken.net/api不要加/v1。model_provider的名字要和[model_providers.taotoken]这一段对应改错任何一处都会让 Codex 找不到通道。2.3 Codex 只看 SQL不负责连 SQL Server 执行Codex 在这个流程里的角色是读脚本、解释fetch_status、指出FETCH NEXT位置问题。它不应该、也不需要直接连你的 SQL Server。诊断 SQL 和修正后的游标脚本都由你在 SSMS、sqlcmd 或 VS Code 的数据库插件里手动执行再把结果贴回对话。把生产库连接串交给 AI 工具既没必要也会把简单排障变成权限问题。如果你在对话里写“帮我连上数据库执行一下”那就偏离了这条排查路径。正确说法是“下面是我本地执行后的 PRINT 输出请对照 0/-1/-2 帮我判断FETCH NEXT应该放在哪里。” Codex 只做代码审查和解释执行动作留在你的机器上。3. 把 fetch_status 报错丢给 Codex 时提示词要带哪三样东西3.1 第一样完整游标脚本与 FETCH NEXT 的位置只发一句“fetch_status 总是 -1”没有信息量。把DECLARE、OPEN、FETCH NEXT、WHILE、BEGIN/END、CLOSE、DEALLOCATE全贴进去再标出你实际处理数据的那几行。Codex 需要看到FETCH NEXT是在WHILE条件前、BEGIN第一行还是BEGIN最后一行。提示词可以这样写下面这段 SQL Server 游标在最后一行后fetch_status变成 -1循环多执行一次。只检查FETCH NEXT与WHILE的位置不要改业务逻辑给出修正脚本和逐轮状态说明。把业务表的真实列名和 Northwind 示例区分开避免 Codex 把示例表名当成你的线上表。3.2 第二样本地跑出来的 0/-1/-2 观察结果在本地 SSMS 里加PRINT把每一轮的行数据和状态打出来。下面这段诊断脚本只读 Northwind 示例不改业务表。执行后把消息窗口结果复制给 Codex。DECLARE LastName nvarchar(20), FirstName nvarchar(20); DECLARE Employee_Cursor CURSOR LOCAL FAST_FORWARD FOR SELECT LastName, FirstName FROM Northwind.dbo.Employees ORDER BY LastName, FirstName; OPEN Employee_Cursor; FETCH NEXT FROM Employee_Cursor INTO LastName, FirstName; PRINT CONCAT(循环前 FETCH NEXTstatus, FETCH_STATUS); WHILE FETCH_STATUS 0 BEGIN PRINT CONCAT(处理当前行, LastName, N, , FirstName, N | 进入循环时 status, FETCH_STATUS); FETCH NEXT FROM Employee_Cursor INTO LastName, FirstName; PRINT CONCAT(本轮 FETCH NEXT 后 status, FETCH_STATUS); END; CLOSE Employee_Cursor; DEALLOCATE Employee_Cursor;如果最后一行后面出现本轮 FETCH NEXT 后 status-1而它下面又执行了一次“处理当前行”就说明FETCH NEXT的位置不对。如果状态在进入循环时就已经是 -1检查OPEN和第一次FETCH NEXT是否执行。如果状态在循环中间突然变成 -1而你并没有取到边界行优先怀疑嵌套游标覆盖了全局状态。3.3 第三样把本地执行结果贴回对话让 Codex 对照状态表Codex 不执行 SQL但它很擅长把PRINT输出和fetch_status三种值做对照。把消息窗口里的行、status、循环次数一起贴过去让它判断是跳过首行、重复末行还是嵌套游标覆盖状态。你还可以让 Codex 生成一张逐轮状态表列出“进入循环时 status”“处理的行”“本轮 FETCH 后 status”这样循环终止条件哪里写错会一目了然。这样得到的是代码审查结论不是让 AI 去连库执行。你贴的是输出不是账号Codex 给的是修改建议不是生产操作。4. 嵌套游标和 OPEN/DEALLOCATE 也会让 fetch_status 看起来“总是 -1”4.1 内层 FETCH 覆盖外层状态fetch_status是全局变量一个会话里只有一份。外层游标正在循环内层游标执行一次FETCH NEXT外层读到的fetch_status就变成内层的结果。外层如果在内层FETCH后立刻检查WHILE条件就可能提前退出。修法是把外层FETCH NEXT放到循环体最后确保下一次WHILE判断前最后执行的FETCH属于外层游标。DECLARE OuterId int, InnerId int; DECLARE OuterCursor CURSOR LOCAL FAST_FORWARD FOR SELECT Id FROM dbo.OuterTable; DECLARE InnerCursor CURSOR LOCAL FAST_FORWARD FOR SELECT Id FROM dbo.InnerTable; OPEN OuterCursor; OPEN InnerCursor; FETCH NEXT FROM OuterCursor INTO OuterId; WHILE FETCH_STATUS 0 BEGIN -- 内层游标处理 FETCH NEXT FROM InnerCursor INTO InnerId; -- 关键外层取下一行放在循环体最后 FETCH NEXT FROM OuterCursor INTO OuterId; END; CLOSE InnerCursor; DEALLOCATE InnerCursor; CLOSE OuterCursor; DEALLOCATE OuterCursor;如果你必须在内层处理前保存外层状态可以用局部变量先存一份。但更简单的做法是避免嵌套游标改成集合操作或临时表。游标嵌套越深fetch_status越容易变成“谁最后 FETCH 谁说了算”。4.2 游标未 OPEN、已 DEALLOCATE 或作用域不对OPEN之前FETCH状态是 -1CLOSE或DEALLOCATE之后再FETCH状态还是 -1游标变量离开作用域后续FETCH也会失败。用LOCAL FAST_FORWARD可以减少全局游标和滚动游标带来的干扰。检查顺序是DECLARE是否在执行块内、OPEN是否真的执行、FETCH是否在OPEN之后、DEALLOCATE是否提前执行。还有一种情况是动态 SQL 里创建游标外部再FETCH。动态 SQL 的作用域和普通语句不同游标可能根本不存在于当前会话。把创建、打开、取数放在同一个执行块里排障会简单很多。4.3 结果集为空或变量类型不匹配如果SELECT返回 0 行第一次FETCH NEXT就是 -1WHILE不会进入这是预期行为。如果INTO的变量类型和列类型不匹配FETCH可能直接失败并返回 -1。还有fetch_status -2表示被提取的行不存在通常在取数后行被删除或游标滚动到已不存在的行时出现。先把 -1 和 -2 分开再谈循环位置。排障时可以在FETCH NEXT前后各加一条PRINT同时打印ROWCOUNT和关键变量值。变量没变、状态变 -1多半是取不到下一行变量变成 NULL、状态变 -1可能是类型或数据问题。5. 修正后的 Employee_Cursor 在本地怎么验证PRINT 状态 行数对照5.1 用 SELECT COUNT(*) 与打印行数对账修正脚本跑完后先别急着回业务代码。用SELECT COUNT(*)拿到源表行数再数PRINT输出了多少行。正确情况下两者一致最后一条PRINT后面只出现一次status-1且不会再打印“处理当前行”。如果打印行数比COUNT多一行说明FETCH NEXT放在了处理逻辑之后末行被重复少一行说明首行被跳过。SELECT COUNT(*) AS SourceRows FROM Northwind.dbo.Employees;对账时把ORDER BY也考虑进去。游标结果集如果没有稳定排序FETCH NEXT的顺序可能和SELECT看到的顺序不同行数对得上但内容顺序对不上。业务逻辑依赖顺序时在游标定义里写清楚ORDER BY。5.2 让 Codex 只做差异解释不碰生产库把COUNT(*)结果、PRINT输出、修正前后脚本一起贴给 Codex让它解释差异。不要让它连接生产库也不要让它生成会直接操作数据的命令。TaoToken 提供的只是模型通道Codex 负责生成和解释 SQL执行动作留在本地。如果 Codex 给出的修正建议里包含“先删除临时表”“重建索引”之类步骤先在自己的测试库验证。AI 可以帮你找到FETCH NEXT位置问题但不应替你决定生产库上的写操作。5.3 验证通过后再推广到其他游标一个游标改对不代表全库游标都没问题。把修正模板保存成代码片段重点检查四种模式FETCH NEXT是否在BEGIN第一行WHILE条件是否直接读fetch_status内层游标后是否还有外层FETCHCLOSE和DEALLOCATE是否成对。逐条替换比全局搜索替换安全。批量检查时可以让 Codex 帮你写一个只读的查询从系统视图里找包含fetch_status的存储过程和函数文本。查询结果仍然由你在本地执行再把需要的片段贴回对话分析。6. 排查结束后去 TaoToken 控制台对一下 Codex 这次调用6.1 用同一把 Key 在模型对话里发测试消息配置保存后先在 TaoToken 模型对话 里用同一把 Key 发一条测试消息确认模型 ID 和 Base URL 没填错。如果 Codex 报 404第一眼先看base_url是不是多写了/v1如果报 401回 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 检查 Key 是否复制完整、环境变量是否在当前终端生效。测试消息不要发生产 SQL发一句普通问题即可。通道通了再回到 Codex 里贴游标脚本。这样能把“网络通道问题”和“SQL 逻辑问题”拆开不会在fetch_status上浪费半天。6.2 长期排查 SQL 就看 Coding Plan 和 Key 管理如果你打算长期用 Codex 帮你审查游标、存储过程和动态 SQL可以打开 Coding Plan 看套餐是否够用。多项目、多把 Key 的情况统一在 控制台 API Keys 创建和轮换别把 Key 写进脚本或提交到仓库。控制台里还能看到调用记录排查完fetch_status之后顺手对一下这次 Codex 会话有没有记上账。如果用量和预期差太多先检查是不是模型 ID 配错或者同一个 Key 被多个工具共用。6.3 如果团队也用 Claude Code接入文档在这里同一套 Base URLhttps://taotoken.net/api也可以接到其他兼容工具上。团队里有人用 Claude Code 的话对照 Claude Code 接入文档 配ANTHROPIC_BASE_URL、ANTHROPIC_AUTH_TOKEN和ANTHROPIC_MODEL不要把 Codex 的config.toml和 Claude Code 的环境变量混在一起。两套工具可以共用一把 Key但配置文件各写各的排障时才不会互相干扰。
返回列表