MSSQL2008 - Pyodbc - 以前的SQL不是查询

时间:2011-10-13 12:03:47

标签: python windows sql-server-2008 pyodbc

我无法弄清楚以下代码有什么问题, 语法是正确的(使用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.

任何人都知道为什么会这样? 我得到了一个&#34; SQL Server&#34;安装驱动程序(默认情况下),针对Windows 2008 SQL Server环境运行Windows 7(不是快速数据库)。

9 个答案:

答案 0 :(得分:51)

为了防止一些孤独的网络游牧民遇到这个问题,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

答案 1 :(得分:3)

我得到了这个,因为我正在重复使用我正在循环的光标:

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(...)

答案 2 :(得分:2)

正如其他人所说,SET NOCOUNT ON将在存储过程中处理额外的结果集,但是其他事情也会导致NOCOUNT无法阻止的额外输出(以及pyodbc将作为结果集看到),例如忘记删除调试存储过程后的print语句。

答案 3 :(得分:1)

正如特拉维斯(Travis)和其他人所提到的,其他情况也可能导致SET NOCOUNT ON无法阻止的额外输出。

我在过程开始时将SET NOCOUNT设置为ON,但是在结果集中收到警告消息。

我在脚本开始处设置了ansi警告,以删除错误消息。

SET ANSI_WARNINGS OFF

希望这对某人有帮助。

答案 4 :(得分:0)

首先关闭:

如果您运行的是Windows SQL Server 2008,请使用SQL软件安装中包含的“Native Client”(它随数据库和Toolkits一起安装,因此您需要安装Microsoft SQL Management应用程序) )

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

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

这应该可以解决问题!

答案 5 :(得分:0)

如果您的SQL不是Stored Proc。

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

改为使用'is not null'。

答案 6 :(得分:0)

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

就我而言,还必须删除此行:

Use DatabaseName;

数据库是SQL Server 2012, Python 3.7, SQL炼金术1.3.8

希望这对某人有帮助。

答案 7 :(得分:0)

如果您的存储过程调用 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.

答案 8 :(得分:-1)

我已通过将 use数据库 sql查询分成两个execute语句解决了这个问题。