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

资讯详情

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

Excel使用ADO调用SQL Server存储过程:TaoToken统一Key通道下的参数化配置与结果回写

Excel使用ADO调用SQL Server存储过程:TaoToken统一Key通道下的参数化配置与结果回写 1. Excel VBA 调用 SQL Server 存储过程为什么总返回 -1 行很多做报表自动化的朋友都遇到过这个场景Excel 里点一下按钮把 SQL Server 里算好的结果拉回来填到工作表。用SELECT语句时一切正常换成EXECUTE dbo.usp_GetScore调用存储过程RecordCount就变成 -1循环写不进去工作表一片空白。这个坑我在做现场投票统计时踩过排查了大半天才定位到是游标位置的问题。先把问题说清楚。ADO 的Recordset对象有个CursorLocation属性默认值是adUseServer常量 2表示用数据提供程序或驱动提供的服务端游标。服务端游标对数据变化高度敏感能看到其他用户对数据源的修改多用户场景下有优势。但代价是记录集行数不确定RecordCount可能返回 -1BOF/EOF判断也可能不准。而adUseClient常量 3使用本地游标库提供的客户端游标功能更完整RecordCount能拿到真实行数遍历写入就稳了。那为什么SELECT没事、存储过程就翻车因为直接SELECT时 ADO 有时会走另一条取数路径行数能拿到而EXECUTE存储过程返回的结果集在服务端游标下更容易出现行数不可知的情况。解决办法有两个一是把CursorLocation显式设为adUseClient再Open二是干脆不遍历直接用CopyFromRecordset把记录集整块粘到工作表这个方法不依赖RecordCount。这篇内容面向的是需要用 Excel 做数据回写、又想把复杂计算放到数据库端的同学。适合谁做投票统计、绩效汇总、库存对账这类Excel 当界面、SQL Server 当计算引擎的岗位。下面我会把连接串、Command 对象、参数绑定、结果回写、错误捕获整条链路拆开讲代码可以直接复制改改就用。另外如果你在多个环境测试库、生产库、不同项目之间切换连接配置手动改连接串很容易出错我会顺带讲一下怎么用统一的 Key 通道来管理这些凭证避免把密码硬编码在 VBA 里。核心检索词先明确Excel 通过 ADO 调用 SQL Server 存储过程关键在三处——连接字符串、Command 参数绑定、游标与结果回写方式。把这三处配对整条链路就通了。2. TaoToken 统一 Key 通道把连接凭证从 VBA 里挪出去先说清楚 TaoToken 在这里扮演什么角色。它不是数据库也不替代 SQL Server而是一个统一管理 API Key 和访问凭证的通道。你可以在官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 注册后在控制台里创建和管理 Key把原本散落在各个 VBA 模块、配置文件里的连接凭证集中起来。对于需要频繁切换数据库环境、或者团队多人共用一套脚本的场景这能省掉大量改密码—发文件—再改回来的来回。为什么要在讲 ADO 之前先提这个因为很多人的连接串是这么写的Providersqloledb;Server192.0.168.1;DatabaseMyTMP;Uidsa;Pwd111111。密码明文躺在 VBA 里工作簿一发给同事密码就跟着走了。更麻烦的是测试库和生产库的地址、账号不同每次切换都要改代码改错一个字符就连不上。统一 Key 通道的思路是VBA 里只保留一个读取凭证的函数真正的地址和 Key 从外部配置或接口拿代码本身不含敏感信息。具体怎么落地分两步。第一步在 TaoToken 控制台创建 Key拿到形如sk-xxxx的凭证并记录你的服务端点。第二步在 VBA 里写一个轻量的读取函数从环境变量或本地配置文件读取而不是硬编码。下面是一个配置模板你可以放在工作簿同目录的config.json里注意这是本地配置示例实际凭证请通过控制台管理不要提交到代码仓库{ sqlServer: { provider: sqloledb, server: 192.0.168.1, database: MyTMP, uid: report_user, pwdFromEnv: SQL_PWD }, taotoken: { baseUrl: https://taotoken.net/api, apiKeyEnv: TAOTOKEN_API_KEY, modelId: your-model-id } }这里pwdFromEnv和apiKeyEnv存的是环境变量名不是密码本身。VBA 用Environ(SQL_PWD)去取这样工作簿里就没有明文了。如果你还想让 Excel 顺带调用模型做数据摘要或异常说明baseUrl填https://taotoken.net/apiKey 从环境变量读模型 ID 按控制台里可用的填。三件套——Base URL、Key、Model ID——缺一不可后面排障章节会专门讲这三个对不上的报错。需要提醒的是TaoToken 管的是访问凭证和通道不改变 SQL Server 本身的账号权限。数据库该给的EXECUTE权限、该建的登录名还是要在 SQL Server 侧配好。把这两层分清楚后面配置才不会乱。控制台入口在这里https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content Key 管理在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 遇到参数不确定时对着文档核对。3. 可复制的 VBA 模块与连接配置模板这一节给完整可跑的代码。先建测试数据再建存储过程最后写 VBA。SQL Server 侧建表和存储过程IF OBJECT_ID(dbo.MyScore) IS NOT NULL DROP TABLE dbo.MyScore; IF OBJECT_ID(dbo.MyPerson) IS NOT NULL DROP TABLE dbo.MyPerson; GO CREATE TABLE dbo.MyScore(PersonID int, ProjectID int, ProjectScore int); CREATE TABLE dbo.MyPerson(PersonID int, IsExpert int); INSERT INTO dbo.MyScore VALUES (1,1001,90),(1,1002,80),(1,1003,95), (2,1001,85),(2,1002,85),(2,1003,90), (3,1001,100),(3,1002,90),(3,1003,95); INSERT INTO dbo.MyPerson VALUES (1,0),(2,0),(3,1); GO CREATE PROCEDURE dbo.usp_GetScore MinScore int 0 AS BEGIN SELECT ProjectID, AVG(ProjectScore) AS ProjectScore FROM dbo.MyScore WHERE ProjectScore MinScore GROUP BY ProjectID; END; GO注意这里我给存储过程加了一个MinScore参数用来演示参数绑定。带参调用是很多人卡住的地方——用字符串拼接EXECUTE dbo.usp_GetScore 80能跑但拼接有注入风险参数类型也容易错。正确做法是用ADODB.Command对象加Parameters.Append。VBA 模块完整版如下包含连接、参数绑定、结果回写和错误捕获Option Explicit 从环境变量读取密码避免硬编码 Private Function GetConnString() As String Dim pwd As String pwd Environ(SQL_PWD) If Len(pwd) 0 Then Err.Raise vbObjectError 1001, , 环境变量 SQL_PWD 未设置 End If GetConnString Providersqloledb;Server192.0.168.1; _ DatabaseMyTMP;Uidreport_user;Pwd pwd ; End Function Sub CallStoredProcWithParam() Dim cn As ADODB.Connection Dim cmd As ADODB.Command Dim rs As ADODB.Recordset Dim prm As ADODB.Parameter Dim ws As Worksheet Dim rowCount As Long Set ws ThisWorkbook.Worksheets(Sheet1) Set cn New ADODB.Connection Set cmd New ADODB.Command Set rs New ADODB.Recordset On Error GoTo ErrHandler cn.Open GetConnString() If cn.State adStateOpen Then MsgBox 数据连接失败, vbOKOnly, 提示 Exit Sub End If 清空旧数据并写表头 ws.Cells.ClearContents ws.Range(A1).Value 参评项目ID ws.Range(B1).Value 平均分值 用 Command 对象绑定参数避免字符串拼接 Set cmd.ActiveConnection cn cmd.CommandText dbo.usp_GetScore cmd.CommandType adCmdStoredProc cmd.Parameters.Append cmd.CreateParameter(MinScore, adInteger, adParamInput, , 80) 关键客户端游标RecordCount 才准确 rs.CursorLocation adUseClient Set rs cmd.Execute If Not (rs.BOF And rs.EOF) Then rowCount rs.RecordCount 方式一遍历写入 Dim i As Long For i 2 To rowCount 1 ws.Cells(i, 1).Value rs.Fields(0).Value ws.Cells(i, 2).Value rs.Fields(1).Value rs.MoveNext Next i 方式二更省事整块粘贴注释掉上面循环即可 ws.Range(A2).CopyFromRecordset rs Else rowCount 0 End If MsgBox 写入行数 rowCount, vbOKOnly, 执行结果 CleanExit: If Not rs Is Nothing Then If rs.State adStateOpen Then rs.Close Set rs Nothing End If If Not cn Is Nothing Then If cn.State adStateOpen Then cn.Close Set cn Nothing End If Exit Sub ErrHandler: MsgBox 错误 Err.Number Err.Description, vbCritical, 执行失败 Resume CleanExit End Sub几个要点。第一cmd.CommandType adCmdStoredProc告诉 ADO 这是存储过程不要当普通 SQL 解析。第二CreateParameter的四个关键参数是名称、类型、方向、大小输入参数大小可省略但类型要对上MinScore是 int 就用adInteger。第三rs.CursorLocation adUseClient必须在cmd.Execute之前设设晚了不生效。第四CopyFromRecordset那行是备选方案不依赖RecordCount数据量大时比逐格写快很多。引用库别忘了VBE 里工具—引用勾选Microsoft ActiveX Data Objects 6.1 Library或 2.8。没勾的话ADODB.Connection会报用户定义类型未定义。4. 验证请求与成功结果行数比对和错误捕获代码跑通不算完得验证结果对不对。我习惯做三步验证。第一步执行前记录工作表当前已用行数。在ws.Cells.ClearContents之前加一行Dim beforeRows As Long: beforeRows ws.UsedRange.Rows.Count。执行后再取一次afterRows弹窗里同时显示执行前 X 行执行后 Y 行写入 Z 行。这样一眼能看出是不是真的写进去了而不是被清空后没填。第二步对照数据库端的结果。在 SQL Server 里直接跑EXEC dbo.usp_GetScore MinScore 80把返回的 ProjectID 和分值记下来和 Excel 里的逐行核对。测试数据里 1001、1002、1003 三个项目的平均分应该都能算出来且都大于等于 80。如果 Excel 里少了一行多半是RecordCount或循环边界的问题。第三步故意制造错误看捕获是否生效。把连接串里的服务器地址改成一个不存在的 IP执行后应该弹出错误 -2147467259[DBNETLIB][ConnectionOpen]...这类提示而不是 Excel 直接崩掉。再把MinScore传成字符串abc应该报类型转换错误。错误能被ErrHandler接住并弹窗说明整条链路的异常处理是完整的。成功执行后Sheet1 应该是 A1 表头、A2 起三行数据弹窗显示写入行数3。如果弹窗显示 0 但数据库明明有数据回去检查CursorLocation是不是设在了Execute之后。如果弹窗显示 -1说明客户端游标没生效检查引用库版本或改用CopyFromRecordset。还有一个容易被忽略的点cmd.Execute返回的Recordset如果存储过程里有SET NOCOUNT ON行为会更稳定。建议在存储过程开头加上SET NOCOUNT ON;避免行数计数消息干扰 ADO 对结果集的判断。这个细节在官方文档里不显眼但实测能减少不少诡异问题。5. 本篇常见错误排查401、local proxy failed、reading choices、OAuth这一节按真实报错来对。虽然 ADO 连 SQL Server 本身不涉及 OAuth但如果你在同一个工作簿里还调用了模型接口做数据说明就会碰到下面这些。401 Unauthorized。出现在调用模型接口时说明 Key 无效或没带上。检查三件套Base URL 是不是https://taotoken.net/apiKey 是不是从环境变量正确读出Environ(TAOTOKEN_API_KEY)返回空就是没设Model ID 是不是控制台里可用的。三者任一不对都可能 401。注意 Base URL 不要多加路径也不要漏掉/api。local proxy failed。这个报错通常出现在本地网络配置或代理设置干扰了请求。检查系统代理设置确认没有残留的代理配置拦截了到服务端的连接。VBA 里如果用MSXML2.ServerXMLHTTP发请求可以显式设置setProxy 2, 来绕过系统代理。数据库连接串里也不要带任何代理相关参数。reading choices 相关报错。这类错误一般出现在解析接口返回的 JSON 时返回体里没有预期的choices字段。原因可能是请求体格式不对或者 Model ID 填错导致服务端返回了错误结构。先用模型对话页面 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 手动发一条消息确认 Key 和模型可用再回到 VBA 里对照请求体。OAuth 相关报错。如果你用的是需要 OAuth 流程的客户端比如某些编码工具报错通常指向 token 过期或回调地址不匹配。这类场景建议直接看接入文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 里的对应章节按文档重新走一遍授权。VBA 里做 OAuth 比较别扭一般建议把这类调用放到外部脚本Excel 只负责读写结果。数据库侧的常见错误单独列一下。ADODB.Connection报未找到提供程序是没装 SQL Server 客户端驱动或 Provider 名写错sqloledb对应旧版新版可用MSOLEDBSQL。报登录失败检查 Uid/Pwd 和数据库是否允许 SQL 认证。报对象名无效检查存储过程是否在正确的数据库和 schema 下调用时写全dbo.usp_GetScore。排障时建议把On Error GoTo ErrHandler里的Err.Number和Err.Description都打出来光看描述有时不够错误号能帮你快速定位是连接层、命令层还是记录集层的问题。6. 长期编码与 Agent 场景把凭证管理交给 Coding Plan如果你只是偶尔跑一次报表上面的配置够用了。但如果你在持续维护多个 Excel 自动化项目或者想让 Agent 帮你生成和调试 VBA 代码凭证散落各处就会变成负担。这时候可以考虑用 Coding Plan 把 Key 和模型调用统一管起来入口在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。具体怎么配合把数据库连接凭证和模型 Key 都通过统一通道管理VBA 里只保留读取逻辑。Agent 帮你改代码时不需要知道真实密码只需要知道环境变量名。这样代码可以安全地分享、版本管理也不会因为换了个数据库就要全文搜索替换密码。对于 Claude Code 这类编码工具接入时同样遵循三件套原则Base URL 填https://taotoken.net/apiKey 从控制台创建Model ID 按可用列表选。配置写进对应的 settings 文件不要写死在代码里。这样换环境时只改配置不动业务逻辑。回到 Excel ADO 这条链路最终建议是连接串从环境变量或统一配置读存储过程用 Command 对象绑参数记录集设adUseClient或直接用CopyFromRecordset错误捕获覆盖连接、执行、回写三段。把这四点做到Excel 调 SQL Server 存储过程基本不会再翻车。需要看更多接入示例的话文档页 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 里有分场景的说明对着改比自己试错快。
返回列表