【问题标题】:Does FreeTDS ODBC + pyodbc support table-valued parameters (TVPs)?FreeTDS ODBC + pyodbc 是否支持表值参数 (TVP)?
【发布时间】:2021-02-17 20:39:05
【问题描述】:

我正在开发 unix/rhel7 系统。我已经安装了 FreeTDS、unixODBC 和 pyodbc 的必需驱动程序。其他查询工作正常,但是当我尝试使用 TVP(表值参数)执行存储过程时,它给了我错误。有什么方法可以通过 python 使用 windows 服务帐户 连接 SQL Server?

例子:

import pyodbc;

cnxn = pyodbc.connect('DRIVER=FreeTDS;SERVER=SERVERNAME;PORT=1234;UID=USERNAME;PWD=PASSWORD;DATABASE=DBNAME')
cnxn.cursor()


param_array = []
for i in range(3):
  param_array.append(['abc', 'adi', '/somepath/', '2021-01-04', 'NEW'])

result_array = cursor.execute("EXEC abc.stored_proc_name ?", [param_array]).fetchall()
cursor.commit()

cnxn.close()

错误:

pyodbc.Error: ('HY004', '[HY004] [FreeTDS][SQL Server]无效数据类型 (0) (SQLBindParameter)')

那么有没有其他方法可以从支持 TVP 的 python 连接 SQL 服务帐户?或者上面的例子有什么解决办法吗?

【问题讨论】:

  • 我很确定 FreeTDS ODBC 不支持 TVP。但是微软的“ODBC Driver 17 for SQL Server”可以,而且它适用于 RHEL,所以你可以使用它。
  • “ODBC Driver 17 for SQL Server”是否需要安装 Kerberos?还是有其他方法可以做到?
  • 据我所知,如果 SQL Server 实例不支持 SQL 登录(只是“Windows 身份验证”)并且客户端在 Linux 上,那么是的,“ODBC Driver 17 for SQL Server”确实需要 Kerberos .

标签: pyodbc freetds table-valued-parameters


【解决方案1】:

FreeTDS ODBC 不直接支持表值参数 (TVP),如 here 所述。但是我们可以使用临时表和匿名代码块来解决这个问题。对于用户定义的表类型

USE [myDb]
GO

/****** Object:  UserDefinedTableType [dbo].[dboListInt]    Script Date: 2021-02-18 10:53:17 ******/
CREATE TYPE [dbo].[dboListInt] AS TABLE(
    [Id] [int] NOT NULL,
    PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (IGNORE_DUP_KEY = OFF)
)
GO

以及接受该表类型的存储过程

USE [myDb]
GO
/****** Object:  StoredProcedure [dbo].[dboPyOdbcTestTvp]    Script Date: 2021-02-18 10:41:43 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[dboPyOdbcTestTvp](@tvp [dbo].dboListInt READONLY)
AS
BEGIN
    SET NOCOUNT ON;

    SELECT * FROM @tvp

END

我们可以像这样调用存储过程并检索结果:

import pyodbc

cnxn = pyodbc.connect(
    "DRIVER=FreeTDS_1.2.18;"
    "SERVER=192.168.0.179;"
    "PORT=49242;"
    "DATABASE=myDb;"
    "UID=sa;PWD=_whatever_;"
)
crsr = cnxn.cursor()
crsr.execute("CREATE TABLE #tvp_data (Id int)")
tvp_data = [(123, ), (234, ), (345, )]
crsr.executemany(
    "INSERT INTO #tvp_data (Id) VALUES (?)",
    tvp_data
)
crsr.execute("""\
SET NOCOUNT ON;
DECLARE @tvp dbo.dboListInt;
INSERT INTO @tvp (Id)
SELECT Id FROM #tvp_data;
EXEC dbo.dboPyOdbcTestTvp @tvp;
""")
print(crsr.fetchall())
# [(123, ), (234, ), (345, )]

【讨论】:

    猜你喜欢
    • 2015-12-21
    • 2021-12-22
    • 1970-01-01
    • 2011-10-18
    • 1970-01-01
    • 2010-11-03
    • 2019-03-19
    • 1970-01-01
    相关资源
    最近更新 更多