【问题标题】:pyodbc does not throw on SQL Server errorpyodbc 不会引发 SQL Server 错误
【发布时间】:2013-12-10 20:16:46
【问题描述】:

我正在尝试使用pyodbc(使用 Python 2.7)调用存储过程以将记录插入到 SQL Server 2012 表中。我正在传递一个临时表。

我转储了我的 sql,当通过 SQL Server 管理控制台执行时,它产生了以下外键错误:

Msg 547, Level 16, State 0, Procedure spInsertBondTickerValues, Line 26
The INSERT statement conflicted with the FOREIGN KEY constraint "FK__BondTickerValue__756D6ECB".
The conflict occurred in database "QuantDev", table "dbo.Tickers".
The statement has been terminated.

但是,pyodbc 没有引发异常。我将如何测试生成的游标或连接以了解发生了问题,以及如何获取错误消息?

非常感谢。

编辑这是完整的 sql 文本:

DECLARE @rawTbl [dbo].TickerValueTableType
INSERT INTO @rawTbl (Ticker, BBName, LastValue, ValueTime, SourceDescr) VALUES
('IBM', 'Equity', 179.230000, '2013-11-01 00:00:00.000000', 'Bloomberg'),
('SPX', 'Index', 1803.710000, '2013-12-10 00:00:00.000000', 'Bloomberg')
EXEC [dbo].spInsertBondTickerValues @rawTbl

EDIT 2 以下是相关的 Python 代码:

def execSQLwithCommit(self, sql):
    cursor = self.conn.cursor()
    cursor.execute(sql)
    self.conn.commit()

以前通过什么方式建立连接的地方

self.conn = pyodbc.connect(app      = appName,
                           driver   = '{SQL Server Native client 11.0}',
                           server   = server,
                           database = db,
                           Trusted_Connection = 'yes')

【问题讨论】:

  • 请使用 pyodbc.Cursor 实例化和执行的相关 python 代码进行更新。
  • @beargle 完成。谢谢。
  • 您的 SQL 脚本似乎缺少任何分号。我想知道它是否会被解析。 SQL Server 控制台可能足够聪明,可以解析它,但驱动程序同样聪明吗?我还怀疑该脚本包含三个不同的语句,每个语句都可能需要单独的 .execute 调用。
  • @9000 当没有外键错误时,调用会正确插入所有内容。不要认为它是分号或多个语句。将它们分开可能会提供一种测试方法,但我希望 pyodbc 会抛出错误情况......

标签: python sql-server pyodbc


【解决方案1】:

我能够使用以下代码重新创建您的问题,但它会静默失败:

import pyodbc
cnxn = pyodbc.connect('DSN=myDb;')
cursor = cnxn.cursor()
sql = """   
DECLARE @rawTbl dbo.ClientAddressInputType;
INSERT INTO @rawTbl (ClientID, Addr1) VALUES 
(2, 'higgy'), 
(3, 'jiggy'); 
EXEC dbo.AddClientAddress @rawTbl
"""
cursor.execute(sql)
cursor.commit()
cnxn.close()

但是,我可以通过在sql 字符串的开头添加SET NOCOUNT ON; 来获取引发适当IntegrityError 异常的代码:

import pyodbc
cnxn = pyodbc.connect('DSN=myDb;')
cursor = cnxn.cursor()
sql = """   
SET NOCOUNT ON;
DECLARE @rawTbl dbo.ClientAddressInputType;
INSERT INTO @rawTbl (ClientID, Addr1) VALUES 
(2, 'higgy'), 
(3, 'jiggy'); 
EXEC dbo.AddClientAddress @rawTbl
"""
cursor.execute(sql)
cursor.commit()
cnxn.close()

导致

Traceback (most recent call last):
  File "C:\Users\Gord\Desktop\pyOdbc.py", line 12, in <module>
    cursor.execute(sql)
IntegrityError: ('23000', '[23000] [Microsoft][SQL Server Native Client 10.0][SQL Server]The INSERT statement conflicted with the FOREIGN KEY constraint "FK_ClientAddresses_Clients". The conflict occurred in database "myDb", table "dbo.Clients", column \'ClientID\'. (547) (SQLExecDirectW); [01000] [Microsoft][SQL Server Native Client 10.0][SQL Server]The statement has been terminated. (3621)')

【讨论】:

  • 谢谢,会尝试复制,如果可行,将接受。非常感谢您的帮助,我真的很感激。
  • 多年后,经过数小时的调试,您的解决方案帮助了我。谢谢!但是有什么解释为什么这样有效或需要吗?这是pyodbc的错误吗?与 SQL 服务器?还是这是预期的行为?
  • @Cnoor0171 - 这正是 ODBC 在处理 TDS 协议时的工作方式。如果没有SET NOCOUNT ON;,则返回两个“结果”:(1) INSERT 生成的行数,(2) EXEC 的结果,这是一个错误。第一个结果不是错误,如果我们调用.nextset,我们只能从 EXEC 中“看到”错误。对于SET NOCOUNT ON;,来自 EXEC 的错误是返回的第一个(也是唯一一个)结果,因此 pyodbc 会立即注意到它。
  • @GordThompson 所以如果同一个sql字符串中有多个语句,并且除了第一个语句之外的任何一个都有错误,直到调用.nextset才会报告?这有点可怕,但很高兴知道。谢谢!
  • 8 年后,这个修复仍然是让多行语句在 Python 中引发异常的解决方案。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-08
  • 1970-01-01
  • 1970-01-01
  • 2010-10-10
  • 1970-01-01
相关资源
最近更新 更多