![](/img/trans.png)
[英]How to access a SQL Server 2008 stored procedure with a table valued parameter in Python
[英]Python call sql-server stored procedure with table valued parameter
我有一個加載、轉換和計算數據的 python 腳本。 在 sql-server 中有一個存儲過程,它需要一個表值參數、2 個必需參數和 2 個可選參數。 在 sql server 中,我可以調用這個 SP:
USE [InstName]
GO
DECLARE @return_value int
DECLARE @MergeOnColumn core.MatchColumnTable
INSERT INTO @MergeOnColumn
SELECT 'foo.ExternalInput','bar.ExternalInput'
EXEC @return_value = [core].[_TableData]
@Target = N'[dbname].[tablename1]',
@Source = N'[dbname].[table2]',
@MergeOnColumn = @MergeOnColumn,
@Opt1Param = False,
@Opt2Param = False
SELECT 'Return Value' = @return_value
GO
經過全面搜索,我找到了以下帖子:
如何使用需要用戶定義類型表參數的 SQLAlchemy 調用存儲過程
它建議使用 PYTDS 和 sql-alchemy 的方言“sql alchemy pytds”來調用具有表值參數的 SP。 通過這篇文章和文檔,我創建了以下 Python 腳本:
import pandas as pd
import pytds
from pytds import login
import sqlalchemy as sa
from sqlalchemy import create_engine
import sqlalchemy_pytds
def connect():
return pytds.connect(dsn='ServerName',database='DBName', auth=login.SspiAuth())
engine = sa.create_engine('mssql+pytds://[ServerName]', creator=connect)
conn = engine.raw_connection()
with conn.cursor() as cur:
arg = ("foo.ExternalInput","bar.ExternalInput")
tvp = pytds.TableValuedParam(type_name="MergeOnColumn", rows=(arg))
cur.execute('EXEC test_proc %s', ("[dbname].[table2]", "[dbname].[table1]", tvp,))
cur.fetchall()
當我運行此代碼時,我收到以下錯誤消息:
TypeError: not all arguments converted during string formatting
有誰知道如何正確傳遞多個參數或有我如何直接處理這個調用 SP 的建議?
根據對我的問題的評論,我設法使用表值參數運行存儲過程(並從 SP 獲取返回值)最終腳本如下:
import pandas as pd
import pytds
from pytds import login
import sqlalchemy as sa
from sqlalchemy import create_engine
import sqlalchemy_pytds
def connect():
return pytds.connect(dsn='ServerName',database='DBName',autocommit=True, auth=login.SspiAuth())
engine = sa.create_engine('mssql+pytds://[ServerName]', creator=connect)
conn = engine.raw_connection()
with conn.cursor() as cur:
arg = [["foo.ExternalInput","bar.ExternalInput"]]
tvp = pytds.TableValuedParam(type_name="core.MatchColumnTable", rows=arg)
cur.execute("EXEC test_proc @Target = N'[dbname].[tablename1]', @Source = N'[dbname].[table2]', @CleanTarget = 0, @UseColumnsFromTarget = 0, @MergeOnColumn = %s", (tvp,))
result = cur.fetchall()
print(result)
在連接中添加了自動提交(以提交游標中的事務),表值參數(marchcolumntable)需要 2 列,因此修改了 arg 以適合 2 列。
除了 tvp 之外所需的參數都包含在 exec 字符串中。 執行字符串中的最后一個參數是用 tvp 填充的 tvp 參數(mergeoncolumn)的名稱。
您可以選擇添加 pytds 文檔中描述的結果狀態或行數: https ://python-tds.readthedocs.io/en/latest/index.html
筆記! :在存儲過程中,您必須確保添加了 SET NOCOUNT ON,否則您不會將任何結果返回給 Python
使用純 Python TDS(表格數據流)協議實現的 MSSQL 的 Python DBAPI 驅動程序
我通過針對 SQL Server 的存儲過程使用pytds進行合並/更新插入。
下面是一個基本函數的例子,一行數據用元組表示:
def get_connection(instance: str, database: str, user: str, password: str):
return pytds.connect(
dsn=instance, database=database, user=user, password=password, autocommit=True
)
def execute_with_tvp(connection: pytds.Connection, procedure_name: str, rows: list):
with connection.cursor() as cursor:
tvp = pytds.TableValuedParam(type_name=my_type, rows=rows)
cursor.callproc(procedure_name, tvp)
pyodbc 在 2018-12-13 發布的 4.0.25 版本中添加了對表值參數 (TVP) 的支持。 只需將 TVP 值作為元組列表提供:
proc_name = "so51930062"
type_name = proc_name + "Type"
# set up test environment
with engine.begin() as conn:
conn.exec_driver_sql(f"""\
DROP PROCEDURE IF EXISTS {proc_name}
""")
conn.exec_driver_sql(f"""\
DROP TYPE IF EXISTS {type_name}
""")
conn.exec_driver_sql(f"""\
CREATE TYPE {type_name} AS TABLE (
id int,
txt nvarchar(50)
)
""")
conn.exec_driver_sql(f"""\
CREATE PROCEDURE {proc_name}
@prefix nvarchar(10),
@tvp {type_name} READONLY
AS
BEGIN
SET NOCOUNT ON;
SELECT id, @prefix + txt AS new_txt FROM @tvp;
END
""")
#run test
with engine.begin() as conn:
data = {"prefix": "new_", "tvp": [(1, "foo"), (2, "bar")]}
sql = f"{{CALL {proc_name} (:prefix, :tvp)}}"
print(conn.execute(sa.text(sql), data).fetchall())
# [(1, 'new_foo'), (2, 'new_bar')]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.