You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用pyodbc通过TVP执行存储过程时遇HY090错误求助

pyodbc调用SQL Server表值参数(TVP)时出现HY090错误的排查思路

在Python中使用pyodbc通过表值参数(TVP)执行SQL Server存储过程时,抛出错误:
pyodbc.Error: ('HY090', '[HY090] [Microsoft][ODBC Driver Manager] Invalid string or buffer length (0) (SQLBindParameter)')

该问题仅在PyCharm等编辑器中出现,Jupyter Notebook可正常运行,且pyodbc项目仓库中该问题仍处于开放状态,以下是排查和解决思路。


相关代码定义

TVP类型定义

CREATE TYPE [dbo].[SID_TBL] AS TABLE(
    [Id] [int] NOT NULL,
    [SId] [varchar](50) NOT NULL,
    PRIMARY KEY CLUSTERED 
(
    [SId] ASC
)WITH (IGNORE_DUP_KEY = OFF)
)
GO

存储过程代码

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE [dbo].[GET_STUS] 
    @sid_type dbo.SID_TBL READONLY
AS
BEGIN
    SET NOCOUNT ON;
    select * from dbo.TAB_NAME WITH (NOLOCK)
    WHERE SID IN (SELECT SId FROM @sid_type) 
END

Python执行代码

import pyodbc
import pandas as pd

uid = "admin"
pwd = "abcd1234"
connection_string = (
    r"DRIVER=ODBC Driver 17 for SQL Server;"
    r"SERVER=xxx;"
    r"DATABASE=xxx;"
    f"UID={uid};PWD={pwd};"
)
con = pyodbc.connect(connection_string, autocommit=True)
cur = con.cursor()

s_ids = ["SID_TBL", "dbo"]
a = cur.execute("SELECT TOP 1000 SID FROM TAB_A WHERE <conditions>").fetchall()
ids = list(enumerate([row[0] for row in a]))
s_ids.extend(ids)


sql = "EXEC dbo.GET_STUS @sid_type=?"
params = (s_ids)
result = cur.execute(sql, params).fetchall()

print(pd.DataFrame(result[:100]))

排查与解决思路

  • 修正TVP参数构造格式:当前代码中s_ids的构造不符合pyodbc对TVP的严格要求,且params = (s_ids)未正确构造元组(需改为params = (s_ids,)确保是单元素元组)。建议改用官方推荐的显式列定义方式构造TVP:
    # 正确构造TVP参数
    tvp = (
        "SID_TBL",  # TVP类型名
        [("Id", pyodbc.SQL_INTEGER), ("SId", pyodbc.SQL_VARCHAR, 50)],  # 列类型定义
        ids  # 数据行,每个元素为(int, str)格式的元组
    )
    params = (tvp,)
    
  • 检查环境依赖差异:PyCharm与Jupyter可能使用不同Python环境,导致pyodbc版本或ODBC驱动配置不一致。升级PyCharm环境中的pyodbc到最新稳定版,同时确认ODBC Driver 17 for SQL Server在两个环境中的安装路径、版本一致。
  • 调整连接参数:当前连接设置了autocommit=True,部分场景下自动提交会干扰TVP的参数绑定逻辑。尝试移除autocommit=True,改为手动控制事务:
    con = pyodbc.connect(connection_string)
    try:
        cur = con.cursor()
        # 执行存储过程逻辑
        con.commit()
    finally:
        con.close()
    
  • 验证数据合法性:HY090错误常与参数长度不匹配有关,检查ids中是否存在空字符串、长度超过50的SId值,或Id为非整数的异常数据。
  • 显式指定参数类型:执行时通过pyodbc.SQL_SS_TABLE强制指定TVP参数类型,避免驱动自动推断错误:
    cur.execute(sql, (pyodbc.Parameter("", pyodbc.SQL_SS_TABLE, s_ids),))
    

内容的提问来源于stack exchange,提问作者user3625533

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 04:05:35