44

我不知道下面的代码有什么问题,语法没问题(用 SQL Management Studio 检查),我可以正常访问,所以它也可以工作。但是由于某种原因,一旦我尝试创建一个表通过 PyODBC 然后它停止工作。

import pyodbc

def SQL(QUERY, target = '...', DB = '...'):
    cnxn = pyodbc.connect('DRIVER={SQL Server};SERVER=' + target + DB+';UID=user;PWD=pass')
    cursor = cnxn.cursor()
    cursor.execute(QUERY)
    cpn = []

    for row in cursor:
        cpn.append(row)
    return cpn

print SQL("CREATE TABLE dbo.Approvals (ID SMALLINT NOT NULL IDENTITY PRIMARY KEY, HostName char(120));")

它失败了:

Traceback (most recent call last):
  File "test_sql.py", line 25, in <module>
    print SQL("CREATE TABLE dbo.Approvals (ID SMALLINT NOT NULL IDENTITY PRIMARY KEY, HostName char(120));")
  File "test_sql.py", line 20, in SQL
    for row in cursor:
pyodbc.ProgrammingError: No results.  Previous SQL was not a query.

有人知道这是为什么吗?我安装了“SQL Server”驱动程序(默认),在 Windows 2008 SQL Server 环境(不是快速数据库)上运行 Windows 7。

4

10 回答 10

99

以防万一一些孤独的网络游牧民族遇到这个问题,Torxed 的解决方案对我不起作用。但以下对我有用。

我正在调用一个 SP,它将一些值插入到表中,然后返回一些数据。只需将以下内容添加到 SP :

SET NOCOUNT ON

它会工作得很好:)

Python代码:

    query = "exec dbo.get_process_id " + str(provider_id) + ", 0"
    cursor.execute(query)

    row = cursor.fetchone()
    process_id = row[0]

SP:

USE [DBNAME]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER procedure [dbo].[GET_PROCESS_ID](
    @PROVIDER_ID INT,
    @PROCESS_ID INT OUTPUT
)
AS
BEGIN
    SET NOCOUNT ON
    INSERT INTO processes(provider_id) values(@PROVIDER_ID)
    SET @PROCESS_ID= SCOPE_IDENTITY()
    SELECT @PROCESS_ID AS PROCESS_ID
END
于 2013-02-20T12:21:21.677 回答
11

使用脚本顶部的“SET NOCOUNT ON”值并不总是足以解决问题。

在我的情况下,也有必要删除这一行:

Use DatabaseName;

数据库是 SQL Server 2012、Python 3.7、SQL Alchemy 1.3.8

希望这可以帮助某人。

于 2019-11-20T03:15:21.610 回答
9

我得到这个是因为我正在重用一个我正在循环的游标:

rows = cursor.execute(...)
for row in rows:
    # run query that returns nothing
    cursor.execute(...)
    # next iteration of this loop will throw 'Previous SQL' error when it tries to fetch next row because we re-used the cursor with a query that returned nothing

改为使用 2 个不同的光标

rows = cursor1.execute(...)
for row in rows:
    cursor2.execute(...)

或在再次使用之前获取第一个游标的所有结果:

改为使用 2 个不同的光标

rows = cursor.execute(...)
for row in list(rows):
    cursor.execute(...)
于 2016-08-07T23:33:36.493 回答
5

正如其他人所涵盖的那样,SET NOCOUNT ON将处理存储过程中的额外结果集,但是其他事情也可能导致 NOCOUNT 不会阻止的额外输出(并且 pyodbc 将视为结果集),例如在调试存储过程后忘记删除打印语句.

于 2017-11-08T21:12:23.967 回答
3

正如 Travis 和其他人所提到的,其他事情也可能导致 SET NOCOUNT ON 不会阻止的额外输出。

我在程序开始时设置了 NOCOUNT ON,但在我的结果集中收到了警告消息。

我在脚本的开头设置了 ansi 警告以删除错误消息。

SET ANSI_WARNINGS OFF

希望这可以帮助某人。

于 2020-01-13T23:02:12.873 回答
1

如果您的存储过程调用 RAISERROR,pyodbc 可能会为该消息创建一个集合。

CREATE PROCEDURE some_sp
AS
BEGIN
    RAISERROR ('Some error!', 1, 1) WITH NOWAIT
    RETURN 777
END

在 python 中,您需要跳过第一组,直到找到包含一些结果的一组(有关详细信息,请参阅https://github.com/mkleehammer/pyodbc/issues/673#issuecomment-631206107)。

sql = """
    SET NOCOUNT ON;
    SET ANSI_WARNINGS OFF;
    DECLARE @ret int;
    EXEC @ret = some_sp;
    SELECT @ret as ret;
    """
cursor = con.cursor()
cursor.execute(sql)

rows = None
#this section will only return the last result from the query
while cursor.nextset():
    try:
        rows = cursor.fetchall()
    except Exception as e:
        print("Skipping non rs message: {}".format(e))
    continue

row = rows[0]
print(row[0])  # 777.
于 2021-07-08T19:32:23.973 回答
0

如果您的 SQL 不是存储过程。

在查询中使用 'xyz != NULL' 将给出相同的错误,即“pyodbc.ProgrammingError:没有结果。以前的 SQL 不是查询。”

请改用“不为空”。

于 2014-01-16T05:49:53.903 回答
0

我认为上述问题的根本原因可能与您在执行例如不会返回结果的 DELETE 查询时收到相同的错误消息这一事实有关。所以如果你跑

 result = cursor.fetchall()

您会收到此错误,因为根据定义,DELETE 操作不会返回任何内容。尝试按照此处的建议捕获异常:如何检查结果集是否为空?

于 2022-01-26T13:45:51.430 回答
-1

首先:

如果您运行的是 Windows SQL Server 2008,请使用 SQL 软件安装中包含的“本机客户端”(它与数据库和工具包一起安装,因此您需要安装 Microsoft 的 SQL 管理应用程序)

其次:在 SQL 连接语句中使用“Trusted_Connection=yes” :

cnxn = pyodbc.connect('DRIVER={SQL Server Native Client 10.0};SERVER=ServerAddress;DATABASE=my_db;Trusted_Connection=yes')

这应该可以解决问题!

于 2011-10-25T14:56:27.197 回答
-1

我通过将use 数据库sql 查询拆分为两个执行语句解决了这个问题。

于 2020-08-19T07:37:09.680 回答