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

如何用SQLAlchemy调用带输出参数的存储过程并解决执行问题

问题:使用SQLAlchemy调用带输出参数的存储过程及INSERT执行异常

我尝试用Python的SQLAlchemy模块调用带输出参数的SQL Server存储过程,获取输出结果时遇到错误,后续给存储过程新增INSERT语句后,又出现Python调用能返回计算结果但数据未插入的异常。

初始SQL存储过程

USE [TestDatabase]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE [dbo].[testPython]
    @numOne int,
    @numTwo int,
    @numSum int OUTPUT

AS
BEGIN
    LINENO 0
    SET NOCOUNT ON;

    SET @numSum = @numOne + @numTwo
END
GO

初始SQLAlchemy代码

import sqlalchemy as db
engine = db.create_engine(f"mssql+pyodbc://{username}:{password}@{dnsname}/{dbname}?driver={driver}")

with engine.connect() as conn:
    outParam = db.sql.outparam("ret_%d" % 0, type_=int)
    result = conn.execute('testPython ?, ?, ? OUTPUT', [1, 2, outParam])
    print(result)

错误提示

TypeError: object of type 'BindParameter' has no len()
上述异常直接导致了以下异常:
SystemError: <class 'pyodbc.Error'> returned a result with an error set

已实现的pyodbc版本

借助pyodbc文档,我已经用pyodbc实现了基础功能,但仍想搞懂SQLAlchemy的正确实现方式:

def testsp():
    query = """
    DECLARE @out int;
    EXEC [dbo].[testPython] @numOne = ?, @numTwo = ?, @numSum = @out OUTPUT;
    SELECT @out AS the_output;
    """
    params = (1,2,)

    connection = pyodbc.connect(f'DRIVER={DRIVER_SQL};SERVER={DNSNAME_SQL};DATABASE={DBNAME_SQL};UID={USERNAME_SQL};PWD={PASSWORD_SQL}',auto_commit=True)
    cursor = connection.cursor()
    cursor.execute(query, params)
    rows = cursor.fetchall()
    while rows:
        print(rows)
        if cursor.nextset():
            rows = cursor.fetchall()
        else:
            rows = None
    cursor.close()
    connection.close()

新增INSERT语句后的问题

当给存储过程加入INSERT语句后,无论用之前的SQLAlchemy方案还是上述pyodbc代码,都能正常返回求和结果,但INSERT操作并未执行。我试过常规INSERT和动态SQL两种写法,且确认用户拥有NumbersTable的SELECT和INSERT权限。

尝试设置autocommit的解决方案

查到资料说需要设置auto_commit为True,我对SQLAlchemy和pyodbc代码都做了修改,但问题依旧:

更新后的SQL存储过程

USE [TestDatabase]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE [dbo].[testPython]
    @numOne int,
    @numTwo int,
    @numSum int OUTPUT

AS
BEGIN
    LINENO 0

    SET NOCOUNT ON;

    -- 注释的动态SQL尝试
    -- DECLARE @query varchar(max)
    -- SET @query = 'INSERT INTO NumbersTable(num1, num2, numSum)
    --              VALUES(' + numOne + ', ' + numTwo ', ' + numSum')'
    -- print(@query)
    -- EXEC(@query)

    SET @numSum = @numOne + @numTwo

    INSERT INTO NumbersTable(num1, num2, numSum)
    VALUES(@numOne, @numTwo, @numSum)

    
END
GO

更新后的SQLAlchemy代码

import sqlalchemy as db

engine = db.create_engine(f"mssql+pyodbc://{username}:{password}@{dnsname}/{dbname}?driver={driver}&autocommit=true")

query = """
DECLARE @out int;
EXEC [dbo].[testPython] @numOne = :p1, @numTwo = :p2, @numSum = @out OUTPUT;
SELECT @out AS the_output;
"""
params = dict(p1=1,p2=2)

with engine.connect() as conn:
    result = conn.execute(db.text(query), params).scalar()
    print(result)

这段代码能返回计算结果3,但NumbersTable中没有新增数据。

SQL端直接测试结果

用同一用户在SQL Server中直接执行存储过程,既能得到求和结果,也能成功插入数据:

EXECUTE AS login = 'UserTest'

DECLARE @out int
EXEC [dbo].[testPython] @numOne = 0, @numTwo = 0, @numSum = @out OUTPUT
SELECT @out as the_output

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 17:48:30