sql-server - 查找 3930 SQL Server 错误的原因

标签 sql-server debugging error-handling

我有一个我写的脚本,它在特定行上给我一个 3930 错误。这是一个简单的更新语句,当我在脚本中运行它时它失败了,但是如果我从脚本中打印变量并手动运行它,那么该行执行正常。有人知道我如何追踪这个错误吗?

该行在游标中执行,并在此循环之前正确运行数百次。如果我让它处理所有记录或更新我的游标查询以仅选择这条记录,我会收到错误消息。

完整的错误信息是:

Msg 3930, Level 16, State 1, Line 160
The current transaction cannot be committed and cannot support operations that write to the log file. Roll back the transaction.

违规行是:

UPDATE [DBName].[dbo].[TableName] 
SET [XXX] = @XXX, [DateEdited] = GETDATE(), [EditedBy] = 'MyUser' 
WHERE [YYY] = @YYY

编辑:

我对查询进行了清理,以便可以将其发布在这里;见下文。有几点需要注意。

1) 对于承包商“ABCDEF”,[FactoryDB].[dbo].[AuditInformation] 中只有一条记录,因此该记录不需要游标 B。我尝试删除光标并保留所有包含的代码,但这修复了错误

2) 删除解析年龄的 try-catch block 也修复了错误,即使它没有被任何剩余代码使用。仅供引用,该代码确实出错并且执行了 catch block 。

--TABLE TO HOLD ERROR MESSAGES
declare @errors TABLE (FormId int, FactoryContractorCode nvarchar(50), FactoryId nvarchar(50), ErrorMessage nvarchar(1000) )

--DECLARE VARIABLES
DECLARE @factoryCode nvarchar(50)
DECLARE @factoryId nvarchar(50)
DECLARE @formId int
DECLARE @auditDate DateTime
DECLARE @totalEmployees int
DECLARE @ageRange nvarchar(50)
DECLARE @ageAverage int
DECLARE @percentageFemale int
DECLARE @percentageMale int
DECLARE @rowIdToUpdate nvarchar(50)

DECLARE @tempFormId int
DECLARE @tempDateString nvarchar(50)
DECLARE @tempAuditDate DateTime

--CURSOR TO LOOP THROUGH ALL FACTORY CODES
DECLARE a CURSOR FOR
    SELECT DISTINCT [FactoryCode] FROM [FactoryDB].[dbo].[AuditInformation] WHERE [FactoryCode] = 'ABCDEF'
OPEN a
FETCH a into @factoryCode
WHILE(@@FETCH_STATUS = 0)
BEGIN
BEGIN TRANSACTION

    --RESET VARIABLES TO NULL
    SET @totalEmployees = NULL
    SET @ageRange = NULL
    SET @formId = NULL
    SET @rowIdToUpdate = NULL
    SET @tempAuditDate = NULL
    SET @auditDate = NULL
    SET @ageAverage = NULL
    SET @percentageFemale = NULL
    SET @percentageMale = NULL
    SET @tempFormId = NULL
    SET @tempDateString = NULL
    SET @factoryId = NULL

    SELECT @factoryId=[ContractorID] FROM [DataDB].[dbo].[ContractorIdentifier] WHERE [ContractorCode] = @factoryCode

    --FIND THE FORM ID WITH THE MOST RECENT DATE
    DECLARE b CURSOR FOR
        SELECT [FormId],[StartDate] FROM [FactoryDB].[dbo].[AuditInformation] WHERE [FactoryCode] = @factoryCode AND NOT [StartDate] IS NULL
    OPEN b
    FETCH b into @tempFormId, @tempDateString
    WHILE(@@FETCH_STATUS = 0)
    BEGIN
        --PARSE THE FORM DATE
        BEGIN TRY
            SET @tempAuditDate = CAST(@tempDateString AS DateTime)
        END TRY
        BEGIN CATCH
            INSERT INTO @errors ([FormId],[FactoryContractorCode],[FactoryId],[ErrorMessage]) VALUES (@tempFormId, @factoryCode, @factoryId, 'Unable to parse date value of: '''+@tempDateString+'''')
        END CATCH

        --FIRST TIME
        IF (@auditDate IS NULL)
        BEGIN
            SET @auditDate = @tempAuditDate
            SET @formId = @tempFormId
        END

        --UPDATE IF THE NEW DATE IS MORE RECENT THAN THE PREVIOUS ONE
        IF(@tempAuditDate > @auditDate)
        BEGIN
            SET @auditDate = @tempAuditDate
            SET @formId = @tempFormId
        END

    FETCH b into @tempFormId, @tempDateString
    END
    CLOSE b
    DEALLOCATE b

    --IF A FORM WAS FOUND WITH A PARSABLE DATE
    IF (NOT @formId IS NULL)
    BEGIN
        --GET AUDIT INFORMATION
        SELECT TOP 1
            @totalEmployees = m.[TotarEmployees]
            ,@ageRange = m.[EmployeeAgeRange]
        FROM [FactoryDB].[dbo].[AuditInformation] g
        INNER JOIN [FactoryDB].[dbo].[AuditData] m on g._form_id = m._form_id
        WHERE g.[_form_id] = @formId

        --PARSE THE AVERAGE AGE FROM THE VARCHAR COLUMN
        BEGIN TRY
            DECLARE @low int
            DECLARE @high int

            SET @low = CAST(LTRIM(RTRIM(SUBSTRING(@ageRange,0,CHARINDEX('-',@ageRange)))) AS int)
            SET @high = CAST(LTRIM(RTRIM(SUBSTRING(@ageRange,CHARINDEX('-',@ageRange)+1,LEN(@ageRange)))) AS int)
            SET @ageAverage = ROUND((@low+@high)/2, 0)
        END TRY
        BEGIN CATCH
            INSERT INTO @errors ([FormId],[FactoryContractorCode],[FactoryId],[ErrorMessage]) VALUES (@formId, @factoryCode, @factoryId, 'Unable to parse age value of: '''+@ageRange+'''')
        END CATCH
    END


    --UPDATE THE FACTORY VIEW TABLE
    SELECT TOP 1 @rowIdToUpdate = [Id] FROM [DataDB].[dbo].[DataTable] WHERE [ContractorID] = @factoryId  AND [DateEdited] < @auditDate ORDER BY [DateEdited] DESC

    IF (NOT @rowIdToUpdate IS NULL)
    BEGIN

        IF(NOT @totalEmployees IS NULL)
            UPDATE [DataDB].[dbo].[EmployeeStats] SET  [TotalEmployees] = @totalEmployees, [DateEdited] = GETDATE(), [EditedBy] = 'LstAD' WHERE [RowIDs] = @rowIdToUpdate
        ELSE
            INSERT INTO @errors ([FormId],[FactoryContractorCode],[FactoryId],[ErrorMessage]) VALUES (@formId, @factoryCode, @factoryId, 'Did not update Total Employees. Value was null or unable to be calculated.')
    END

ROLLBACK
FETCH a into @factoryCode
END
CLOSE a
DEALLOCATE a

--DO SOMETHING WITH THE ERRORS TABLE VARIABLE
SELECT * FROM @errors

最佳答案

事实证明,即使它位于 Try/Catch block 内,错误也会阻止事务的提交。我不知道这一点。我重新编写了“--PARSE THE AVERAGE FROM THE VARCHAR COLUMN”代码以在尝试进行数学计算之前使用 ISNUMERIC 作为检查并解决了问题。感谢评论者的帮助。否则我就想不通了。

关于sql-server - 查找 3930 SQL Server 错误的原因,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12101005/

相关文章:

java - 如何告诉 Java SAX 解析器忽略无效字符引用?

SQL 将日期转换为工作日名称

SQL查询多个表

sql-server - SQLAlchemy 声明式 - SQL Server 中的模式和外键/主键

c - 数组元素被反向打印出来

javascript - meteor JavaScript-错误处理

sql-server - 将数据库列表限制为具有 SQL Server 权限的列表

visual-studio - Visual Studio 中调用堆栈窗口的用途是什么?

c++ - 如何找到哪个函数打开了套接字?

jquery - 如果 web 服务返回空结果,如何使用 JSONP 捕获错误