pyodbc连接SQL Server参数化查询报无结果错误如何解决
报错原因
触发pyodbc.ProgrammingError: No results. Previous SQL was not a query.主要是以下问题:
- 核心问题:你的SQL脚本最后执行的是
select S.Keys into #temp语句,这个语句的作用是创建临时表并写入数据,本身不会向客户端返回可读取的结果集,调用fetchall()自然拿不到数据。 - SQL脚本没有加
SET NOCOUNT ON:SQL Server默认会为每个执行的语句返回「影响行数」的消息,pyodbc会将这些消息识别为结果流的一部分,很容易干扰正常结果集的读取。 - 脚本存在隐患和笔误:开头直接执行
drop table #temp,如果临时表不存在会直接报错中断;代码里写的cursor.fecthall()是笔误,正确方法名是fetchall()。 - 额外不规范点:日期参数直接传字符串,容易因为数据库端的区域日期格式配置问题触发隐式转换错误。
正确参数化查询实现
按以下步骤调整即可正常运行:
- SQL脚本开头加
SET NOCOUNT ON;,屏蔽影响行数的消息返回,避免结果流干扰。 - 给临时表删除逻辑加存在性判断,避免表不存在时抛出错误。
- 临时表写入完成后,必须追加
SELECT语句把需要的数据查出来作为最终结果返回。 - 日期参数改为传入Python原生
datetime对象,不要传字符串,规避格式转换问题。 - 修正
fetchall()的拼写错误。
完整可运行代码示例:
from datetime import datetime import pyodbc # 建议连接字符串直接指定目标数据库,无需在SQL中写USE [Data] conn = pyodbc.connect( "DRIVER={ODBC Driver 17 for SQL Server};" "SERVER=你的数据库实例地址;" "DATABASE=Data;" "UID=你的登录账号;" "PWD=你的登录密码;" ) cursor = conn.cursor() query = """ SET NOCOUNT ON; -- 临时表存在才执行删除 IF OBJECT_ID('tempdb..#temp') IS NOT NULL DROP TABLE #temp; DECLARE @MonthStartDate date DECLARE @MonthEndDate datetime DECLARE @LastOpenDate datetime SELECT @MonthStartDate = ? SELECT @MonthEndDate = ? SELECT @LastOpenDate = DATEADD(dd, 7, @MonthEndDate) SELECT S.Keys INTO #temp FROM DataJobs J INNER JOIN DataSent S ON J.Id = S.Id WHERE S.EventDate BETWEEN @MonthStartDate AND @MonthEndDate GROUP BY S.Key HAVING COUNT(DISTINCT S.D) >= 20; -- 最终查询返回需要的结果集 SELECT Keys FROM #temp; """ # 传入datetime类型参数,避免日期格式转换问题 params = ( datetime(2015, 4, 1), datetime(2015, 4, 30, 23, 59, 59, 999000) ) cursor.execute(query, params) result = cursor.fetchall()
补充说明:
- 你脚本中声明的
@LastOpenDate变量没有被后续逻辑使用,属于冗余代码,不影响执行,不需要的话可以直接删除。- 如果后续脚本需要执行多个返回结果集的语句,可以调用
cursor.nextset()切换到下一个结果集再读取,当前单结果场景不需要调用。
内容的提问来源于stack exchange,提问作者Zaynaib Giwa
相关产品推荐
相关产品推荐

