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

pyodbc执行SQL Server存储过程无报错但每次运行结果不一致

问题根因

出现这个问题的核心是pyodbc默认未完整消费存储过程返回的所有结果流,就提前触发事务提交,导致存储过程的循环插入逻辑被随机中断:

  • 你在SSMS中执行存储过程时,SSMS会同步等待整个存储过程的所有逻辑执行完毕、所有返回结果全部接收完成后才结束操作,因此循环会完整跑完所有插入步骤,每次生成的表数据完全一致。
  • 你的存储过程循环中使用SELECT @dateFrom = DATEADD(day, 1,@dateFrom)做变量赋值,这个写法默认会向客户端返回每次赋值的行计数结果(也就是"DONEINPROC"消息)。pyodbc的execute()方法在拿到第一个返回结果后就会认为语句执行完成,如果你此时直接调用commit(),SQL Server会直接终止该存储过程的后续执行。每次循环执行到哪一步被终止完全是随机的,因此最终查询到的max_date_每次都不一样。
修复方案

二选一即可解决问题:

  • 修改存储过程,关闭隐式结果返回:在存储过程最开头加上SET NOCOUNT ON;,禁止执行过程中返回行计数类的隐式消息,pyodbc就会等待整个存储过程执行完毕后才返回。修改后的存储过程开头如下:
    CREATE PROCEDURE procedure_create_tbl_date_range
    AS
    SET NOCOUNT ON;
       DROP TABLE IF EXISTS tbl_date_range;
       -- 后续原有逻辑保持不变
    
  • 修改Python代码,主动消费完所有结果集:如果不想改存储过程,可以在执行存储过程后,循环调用nextset()拉取完所有返回结果,再执行提交。修改后的Python代码逻辑如下:
    def run_procedure(my_procedure):
        conn = pyodbc.connect('Driver={SQL Server};'
                            'Server=.\SQLEXPRESS;'
                            'Database=my_db;'
                            'Trusted_Connection=yes'
                            )
        cur = conn.cursor()
        try:
            cur.execute(my_procedure)
            # 拉取所有剩余结果集,确保存储过程执行完成
            while cur.nextset():
                pass
            conn.commit()
        except Exception as e:
            conn.rollback()
            print(e)
        finally:
            cur.close()
            conn.close()
    

补充说明:你当前的存储过程循环逻辑会跳过初始的@dateFrom值(2021-12-12),最终生成的日期范围是2021-12-13到2022-12-12,如果需要包含起始日期可以调整赋值和插入的顺序,这个逻辑问题和本次的随机结果故障无关。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 00:48:31