ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

pyodbc 调 SQL Server 存储过程取不到返回结果?让 Codex 走 TaoToken 对着游标查

pyodbc 调 SQL Server 存储过程取不到返回结果?让 Codex 走 TaoToken 对着游标查 1. pyodbc 调 SQL Server 存储过程为什么 for row in cursor 一行都不打印你写了一段很典型的 Python 脚本pyodbc.connect拼连接串conn.cursor()建游标cursor.execute(存储过程名称)调存储过程最后for row in cursor: print(row)想拿到查询结果。结果跑起来要么直接报错要么循环体一次都不进屏幕上干干净净连个空行都没有。这个场景我太熟了。它通常不是存储过程写错了而是三处细节里至少有一处对不上连接串的 DRIVER 写法、execute 的调用方式、游标遍历的时机。SQL Server 的驱动版本不同连接串关键字就不同存储过程如果带参数或者内部有SET NOCOUNT ON返回结果集的行为也会变而 pyodbc 的游标在execute之后如果没正确进入结果集状态for row in cursor就是空转。这篇按排障视角来写把原始代码和本地报错整理好交给 Codex 逐行对照重点盯连接串、execute、游标遍历这三处差异。TaoToken 在这里只负责提供 Key 和兼容通道不参与 Python 代码执行也不替 pyodbc 连数据库——数据库连接始终是你本地环境的事。下面从环境准备到实跑验证一步步来。2. 前置准备TaoToken 提供 Key 与兼容通道不碰你的数据库先把边界说清楚避免误解。TaoToken 是一个模型调用的兼容通道你在这里拿到 Key、配好 Base URL就能让 Codex 这类编码助手正常发起请求。它不会去连你的 SQL Server也不会执行你的 pyodbc 脚本。你的数据库账号、服务器地址、驱动版本全部留在本地。所以这一步只做两件事注册拿 Key把 Codex 的接入地址配好。打开 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 注册账号进入控制台创建 API Key。创建入口在 https://taotoken.net/api-keys 建议给这个 Key 起个能认出来的名字比如codex-pyodbc-debug方便后面区分用途。拿到 Key 之后Codex 的 Base URL 填https://taotoken.net/api。注意这里不带/v1也不要加任何查询参数。很多人习惯性补/v1结果请求路径拼错报 404 或者模型列表拉不出来。填完保存重启一下 Codex 让配置生效。如果你后面不只是排这一个 bug而是想长期用编码助手改项目、跑 Agent 任务可以看看 Coding Plan 页面 https://taotoken.net/coding-plan 按用量选合适的档位。只是临时排障的话按量用就行。配好之后先别急着改代码。回到你的本地环境把那段调存储过程的脚本原样跑一遍确认通道可用、请求能正常发出去再进入逐行对照环节。这个顺序很重要先确认工具链通再动业务代码不然报错来源会混在一起。3. 可复制配置连接串、execute、游标遍历三处对照现在进入正题。把下面这段原始代码和你的本地报错一起贴给 Codex让它逐行对照。原始写法大概是这样import pyodbc conn pyodbc.connect(DRIVER{SQL Server};SERVER数据库服务器名称;DATABASE要连接的数据库的名称; UID数据库账户名;PWD数据库密码) cursor conn.cursor() cursor.execute(存储过程名称) for row in cursor: print(row) cursor.close() conn.close()这段代码能跑通的前提很苛刻。下面按三处差异拆开讲。3.1 连接串DRIVER 写错是最常见的坑DRIVER{SQL Server}是旧版 ODBC 驱动的名字对应的是 SQL Server 2000 时代的驱动。现在大多数环境装的是ODBC Driver 17 for SQL Server或ODBC Driver 18 for SQL Server。驱动名对不上pyodbc.connect会直接抛pyodbc.Error: (IM002, [IM002] [Microsoft][ODBC 驱动程序管理器] 未发现数据源名称并且未指定默认驱动程序)。先查本机装了哪些驱动import pyodbc print(pyodbc.drivers())输出里如果有ODBC Driver 17 for SQL Server连接串就改成conn pyodbc.connect( DRIVER{ODBC Driver 17 for SQL Server}; SERVER你的服务器地址,1433; DATABASE你的数据库名; UID你的账号;PWD你的密码; TrustServerCertificateyes; )几个细节SERVER后面带端口用逗号不是冒号TrustServerCertificateyes在自签证书或本地开发环境经常需要否则会报 SSL 相关错误如果用的是 18 版驱动加密默认开启不加这个参数更容易连不上。3.2 execute存储过程名和参数写法cursor.execute(存储过程名称)这种写法如果存储过程不带参数某些情况下能跑但更稳妥的是显式用EXEC或者{CALL ...}语法。带参数时直接拼字符串既容易出错又有注入风险应该用参数占位cursor.execute({CALL 你的存储过程名 (?, ?)}, param1, param2)或者cursor.execute(EXEC 你的存储过程名 p1?, p2?, param1, param2)如果你的存储过程内部有SET NOCOUNT ON它不会影响结果集返回但会影响cursor.rowcount别拿 rowcount 判断有没有数据。3.3 游标遍历execute 之后要正确取结果集for row in cursor本身没问题问题往往出在这个游标当前有没有结果集。如果存储过程先执行了一堆INSERT/UPDATE最后才SELECTpyodbc 默认可能停在第一个受影响行数的状态你需要用nextset()跳到真正的结果集cursor.execute(EXEC 你的存储过程名) while True: if cursor.description is not None: for row in cursor: print(row) if not cursor.nextset(): breakcursor.description为None表示当前不是结果集比如是行数统计跳过它继续nextset()。这样无论存储过程内部有几个语句都能定位到真正的查询结果。把这三处对照整理成表格贴给 Codex 时更清晰位置原始写法常见问题建议写法连接串DRIVER{SQL Server}驱动名过时IM002 报错DRIVER{ODBC Driver 17 for SQL Server}executeexecute(存储过程名称)带参数时拼接易错{CALL 名 (?, ?)}或EXEC 名 p1?遍历for row in cursor多结果集时停在非结果集状态配合cursor.descriptionnextset()4. 验证请求实跑脚本确认返回行正常打印配置改完回到本地实跑。先写一个最小验证脚本只做连接和一次简单查询确认通道和数据库都通import pyodbc conn pyodbc.connect( DRIVER{ODBC Driver 17 for SQL Server}; SERVER你的服务器地址,1433; DATABASE你的数据库名; UID你的账号;PWD你的密码; TrustServerCertificateyes; ) cursor conn.cursor() cursor.execute(SELECT TOP 3 name FROM sys.tables) for row in cursor: print(row) cursor.close() conn.close()如果这三行表名能打印出来说明连接串和游标遍历的基本链路没问题。然后再换成你的存储过程调用cursor.execute({CALL 你的存储过程名 (?, ?)}, param1, param2) while True: if cursor.description is not None: columns [col[0] for col in cursor.description] print(列名:, columns) for row in cursor: print(row) if not cursor.nextset(): break跑通后你会看到列名和每一行数据依次打印。如果列名打出来了但行是空的那问题在存储过程本身的数据逻辑不在 pyodbc 这一层。如果列名都没打出来说明cursor.description一直是None回到 3.3 检查nextset()的循环。这一步的意义在于先用一个已知能返回数据的简单查询确认通道可用再逐步替换成真实存储过程。这样一旦出问题你能立刻判断是环境问题还是代码问题。5. 本篇常见错排查排障时按报错信息对号入座比盲目改代码快得多。IM002 未发现数据源名称驱动名写错或没装。跑pyodbc.drivers()看实际名字照抄进连接串。Login failed for user账号密码或认证模式问题。确认 SQL Server 开了混合认证账号有对应库的权限。SSL Provider 相关错误18 版驱动默认加密。加TrustServerCertificateyes或配好证书。for row in cursor 不执行先看cursor.description是不是None是的话用nextset()往后找结果集。存储过程有返回但 print 不出检查是不是SET NOCOUNT ON加上多语句导致游标停在行数状态。Codex 请求报 404 或模型列表为空Base URL 填成了带/v1的地址。改回https://taotoken.net/api不带后缀。改了配置但没生效Codex 需要重启配置是启动时读取的。把报错原文和你的连接串记得把密码打码一起贴给 Codex让它对照第 3 节的表格逐项检查通常几分钟就能定位到具体哪一处。6. 继续用 Codex 排障时的接入入口排完这个 bug如果你还想让 Codex 帮你继续改 pyodbc 相关代码、加参数校验、处理多结果集接入入口整理在这里创建和管理 Keyhttps://taotoken.net/api-keys接入文档与 Base URL 说明https://taotoken.net/doc想直接在网页里对话验证模型https://taotoken.net/model-chat长期编码和 Agent 任务https://taotoken.net/coding-planBase URL 统一用https://taotoken.net/api不带/v1。数据库连接始终在你本地TaoToken 只负责把 Codex 的请求通道打通。按第 4 节的最小脚本先验证通道再逐步替换成真实存储过程排障会顺很多。
返回列表