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

发布于 2024-12-09 12:37:39 字数 994 浏览 3 评论 0原文

我无法弄清楚以下代码有什么问题, 语法没问题(用 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 环境(不是 Express 数据库)上运行 Windows 7。

I can't figure out what's wrong with the following code,
The syntax IS ok (checked with SQL Management Studio), i have access as i should so that works too.. but for some reason as soon as i try to create a table via PyODBC then it stops working.

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));")

It fails with:

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.

Anyone have any idea to why this is?
I got a "SQL Server" driver installed (it's default), running Windows 7 against a Windows 2008 SQL Server environment (Not a express database).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

想你的星星会说话 2024-12-16 12:37:39

以防万一一些孤独的网络游牧者遇到这个问题,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

Just in case some lonely net nomad comes across this issue, the solution by Torxed didn't work for me. But the following worked for me.

I was calling an SP which inserts some values into a table and then returns some data back. Just add the following to the SP :

SET NOCOUNT ON

It'll work just fine :)

The Python code :

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

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

The 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
最后的乘客 2024-12-16 12:37:39

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

就我而言,还需要删除这一行:

Use DatabaseName;

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

希望这对某人有帮助。

Using the "SET NOCOUNT ON" value at the top of the script will not always be sufficient to solve the problem.

In my case, it was also necessary to remove this line:

Use DatabaseName;

Database was SQL Server 2012,
Python 3.7,
SQL Alchemy 1.3.8

Hope this helps somebody.

み格子的夏天 2024-12-16 12:37:39

我得到这个是因为我重复使用了循环的游标:

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

I got this because I was reusing a cursor that I was looping over:

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

Use 2 different cursors instead

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

or get all results of the first cursor before using it again:

Use 2 different cursors instead

rows = cursor.execute(...)
for row in list(rows):
    cursor.execute(...)
我纯我任性 2024-12-16 12:37:39

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

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

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

SET ANSI_WARNINGS OFF

希望这对某人有帮助。

As Travis and others have mentioned, other things can also cause extra output that SET NOCOUNT ON will not prevent.

I had SET NOCOUNT ON at the start of my procedure but was receiving warning messages in my results set.

I set ansi warnings off at the beginning of my script in order to remove the error messages.

SET ANSI_WARNINGS OFF

Hopefully this helps someone.

阪姬 2024-12-16 12:37:39

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

As others covered, SET NOCOUNT ON will take care of extra resultsets inside a stored procedure, however other things can also cause extra output that NOCOUNT will not prevent (and pyodbc will see as a resultset) such as forgetting to remove a print statement after debugging your stored procedure.

烦人精 2024-12-16 12:37:39

脚本中的每个语句都可以产生一些输出作为数据集或/和作为消息。

select 1 as id

上面最后一行

id
-----------
1

(1 row affected)

是“messages”。如果我对此运行 cursor.fetchall() ,我将得到一个没有任何错误的结果。

但是,如果我的查询是 insert .. into .. 或对不返回数据集的存储过程的调用,则对其执行 fetchall() 会给我一个错误。

有一种方法可以知道获取是否会给我pyodbc.ProgrammingError

if cursor.description:
    cursor.fetchall()

cursor.description具有数据集的所有字段定义它将是None 如果那里什么都没有。

如果脚本中有多个语句,我可以使用 nextset() 迭代数据集。这是阅读完整响应的方法:

def print_current_results(cursor):
    if cursor.messages:
        print(cursor.messages)
    if cursor.description:
        print(cursor.fetchall())

cursor.execute(some_script)
print_current_results(cursor)
while cursor.nextset():
   print_current_results(cursor)

要减少循环数量并最小化总体输出,请使用几乎所有其他答案中提到的 SET NOCOUNT ON 。如果 sql 语句没有生成数据集或消息,那么它会在输出中跳过,这就是您只需 cursor.fetchall() 而不是上面更长的脚本的方法

Every statement in a script could produce some output either as a dataset or/and as a message.

select 1 as id

produce

id
-----------
1

(1 row affected)

Last line above is "messages". If I run cursor.fetchall() on this I will get a result back without any errors.

But if my query is an insert .. into .. or a call to stored procedure that does not return dataset, then fetchall() on it would give me an error.

There is a way to know if fetching would give me pyodbc.ProgrammingError:

if cursor.description:
    cursor.fetchall()

cursor.description has all the field definitions for your dataset It would be None if there is nothing there.

If I have multiple statements in a script I can iterate over datasets with nextset(). Here is a way to read full response:

def print_current_results(cursor):
    if cursor.messages:
        print(cursor.messages)
    if cursor.description:
        print(cursor.fetchall())

cursor.execute(some_script)
print_current_results(cursor)
while cursor.nextset():
   print_current_results(cursor)

To reduce number of loops and minimize the overall output, use SET NOCOUNT ON that is mentioned in almost all other answers. If sql statement has not produced dataset or message then it skipped in output and this is how you can do just cursor.fetchall() instead of above much longer script

深海夜未眠 2024-12-16 12:37:39

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

If your stored procedure calls RAISERROR, pyodbc may create a set for that message.

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

In python, you need to skip the first sets until you find one containing some results (see https://github.com/mkleehammer/pyodbc/issues/673#issuecomment-631206107 for details).

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.
病女 2024-12-16 12:37:39

我认为上述问题的根本原因可能与以下事实有关:当您执行例如不会返回结果的 DELETE 查询时,您会收到相同的错误消息。因此,如果您运行,

 result = cursor.fetchall()

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

I think the root cause of the issue described above might be related with the fact that you receive the same error message when you execute for example a DELETE query which will not return a result. So if you run

 result = cursor.fetchall()

you get this error, because a DELETE operation by definition does not return anything. Try to catch the exception as recommended here: How to check if a result set is empty?

谜兔 2024-12-16 12:37:39

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

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

请改用“不为空”。

In case your SQL is not Stored Proc.

usage of 'xyz != NULL' in query, will give the same error i.e. "pyodbc.ProgrammingError: No results. Previous SQL was not a query."

Use 'is not null' instead.

魂ガ小子 2024-12-16 12:37:39

首先:

如果您运行的是 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')

这应该可以解决问题!

First off:

if you're running a Windows SQL Server 2008, use the "Native Client" that is included with the installation of the SQL software (it gets installed with the database and Toolkits so you need to install the SQL Management applicaton from Microsoft)

Secondly:
Use "Trusted_Connection=yes" in your SQL connection statement:

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

This should do the trick!

三生殊途 2024-12-16 12:37:39

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

I have solved this problem by splitting the use database and sql query into two execute statements.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文