从Python调用的SQL Server存储过程并不总是存储数据,但仍会增加identity coutner

时间:2014-07-21 22:52:20

标签: python sql-server stored-procedures sql-server-2012 pyodbc

我在使用存储过程的SQL Server插入时遇到了一个奇怪的不一致问题。我通过pyodbc从Python调用存储过程通过运行循环来多次调用它以在表中插入多行。

它似乎在大部分时间都能正常工作,但过了一段时间它就会停止在循环中间工作。在那时,即使我尝试通过代码只调用一次它也不会插入任何内容。我没有在Python控制台中收到任何错误消息,实际上我恢复了表格的增量标识,就像数据实际插入一样,但是当我查看数据时,它就不存在了。

如果我从SQL Server Management Studio中调用存储过程并传入数据,它会插入并显示增加的标识号,就像其他记录已插入一样,即使它们不在数据库中。

似乎我对从Python调用存储过程的次数达到了一定的限制,它只是停止工作。

我确保在完成循环遍历插入后断开连接,并且以相同方式编写的其他存储过程通过相同的数据库连接发送仍然照常工作。

我尝试使用SQL Server重新启动计算机,有时它会让我多次从Python调用存储过程,但最终也会停止工作。

我想知道这是否与在循环中调用存储过程太快有关,但这并不能解释为什么在重新启动计算机后,它不再允许存储过程中的任何插入。 / p>

我在线搜索了很多,但没有发现任何类似的内容。

这是存储过程:

USE [Test_Results]
GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE [dbo].[insertStepData]
@TestCaseDataId int,
@StepNumber nchar(10),
@StepDateTime nvarchar(50)
AS
SET NOCOUNT ON;
BEGIN TRANSACTION
DECLARE @newStepId int


INSERT INTO TestStepData (
    TestCaseDataId,
    StepNumber,
    StepDateTime
     )
    VALUES (
    @TestCaseDataId,
    @StepNumber,
    @StepDateTime

)
SET @newStepId = SCOPE_IDENTITY();


SELECT @newStepId
FROM TestStepData

COMMIT TRANSACTION

这是我用来调用存储过程并获取id号的方法('conn'是通过pyodbc的活动数据库连接):

def CallSqlServerStoredProc(self, conn, procName, *args):
    sql = """DECLARE @ret int
             EXEC @ret = %s %s
             SELECT @ret""" % (procName, ','.join(['?'] * len(args)))
    return int(conn.execute(sql, args).fetchone()[0])

以下是我在存储过程中传递的内容:

    ....
    for testStep in testStepData:  

        testStepId = self.CallSqlServerStoredProc(conn, "insertStepData", testCaseId, testStep["testStepNumber"], testStep["testStepDateTime"])

        conn.commit()
        time.sleep(1)

    ....

1 个答案:

答案 0 :(得分:0)

SET @newStepId = SCOPE_IDENTITY();

SELECT @newStepId
FROM StepData

对我来说很可疑:

  1. SCOPE_IDENTITY()返回numeric(38,0),大于int。一段时间后可能会发生转换错误。 更新:现在我们知道IDENTITY列是int,这不是问题(SCOPE_IDENTITY()返回插入当前范围内该列的最后一个值。)

  2. SELECT into variable doesn't guarantee its value if more that one record is returned。此外,我不知道覆盖我们已有的身份价值背后的想法。除此之外,最后一个语句返回的值的数量等于该表中的行数,这会快速增加 - 这可能会导致降级 。简而言之,最后的陈述不仅无用,而且是有害的。

  3. 第二句话也使这些陈述行为不端:

    EXEC @ret = %s %s
    SELECT @ret
    

    由于函数除了RETURN以外只有SELECT一次,因此该块实际上返回两个数据集:1)单个@newStepId值(来自EXEC,产生)由SELECT @newStepId <...>); 2)单个NULL(来自SELECT @ret)。 fetchone()默认读取第一个数据集,因此您不会注意到这一点,但无论如何它都不会对性能或正确性起作用。

    底线

    将第二个语句替换为RETURN @newStepId

    数据不在数据库问题

    我相信它是RETURN之前由COMMIT TRANSACTION引起的。反过来说。

    在原始表单中,我认为这是由长时间工作SELECT和/或possible side-effects from the SELECT not-to-a-variable being inside a transaction引起的。