如何让pyodbc忽略SQL Server的PRINT/RAISERROR消息以避免查询错误?
解决pyodbc执行含PRINT/RAISERROR脚本时fetchall报错的问题
核心原因
ODBC驱动不会把PRINT或RAISERROR('...', 0, 1)的内容判定为错误,这些只是信息级消息。但pyodbc会把每条这类消息当成一个空的"结果集",当你直接调用fetchall()时,cursor还停留在第一个空结果集上,就会触发ProgrammingError: No results. Previous SQL was not a query.错误。
可行解决方案
1. 跳过空结果集,定位到有效查询结果
执行SQL后,用cursor.nextset()循环跳过所有空的消息结果集,直到找到真正的查询结果:
cursor.execute(your_sql_script) # 跳过所有非查询的空结果集 while cursor.nextset(): pass # 现在可以正常获取查询结果 results = cursor.fetchall()
注意:如果脚本包含多个查询结果集,这个方法会跳过前面所有结果,只保留最后一个。如果需要保留多个结果,得调整逻辑逐个判断。
2. 保留调试消息同时获取结果
如果想保留这些调试消息,可先读取cursor.messages属性获取消息内容,再处理结果集:
cursor.execute(your_sql_script) # 读取并输出所有调试消息 for msg in cursor.messages: print(f"调试信息: {msg[1]}") # 切换到有效结果集 while cursor.nextset(): pass results = cursor.fetchall()
如果messages未自动填充,结合循环处理更可靠:
cursor.execute(your_sql_script) # 遍历所有结果集,处理消息并定位到有效数据 while True: # 读取当前结果集的调试消息 for msg in cursor.messages: print(f"调试信息: {msg[1]}") # 切换到下一个结果集,没有则退出循环 if not cursor.nextset(): break # 最后获取查询结果 results = cursor.fetchall()
补充说明
SET NOCOUNT ON这类语句只能抑制计数消息,对PRINT和RAISERROR(0,1)无效,这也是你遇到无法用SET禁用所有消息的原因。- 若脚本有多个查询结果,需要根据实际需求调整
nextset()的循环逻辑,避免误删需要的结果。
内容的提问来源于stack exchange,提问作者Armando Contestabile
相关产品推荐
相关产品推荐

