即使在错误之后,程序也会恢复

时间:2010-07-29 13:30:05

标签: sql-server-2005 stored-procedures error-handling return-value return

以下是我在SQL Server 2005中的过程

PROCEDURE [dbo].[sp_ProjectBackup_Insert]
    @prj_id bigint
    AS
    BEGIN
     DECLARE @MSG varchar(200)
     DECLARE @TranName varchar(200)
     DECLARE @return_value int


    -- 1. Starting the transaction 
     begin transaction @TranName

    -- 2. Insert the records

     SET IDENTITY_INSERT [PMS_BACKUP].[Common].[PROJECT] ON  INSERT INTO [PMS_BACKUP].[Common].[PROJECT] ([PRJ_ID],[PRJ_NO1],[PRJ_NO2],[PRJ_NO3],[PRJ_DESC],[IS_TASKFORCE],[DATE_CREATED],[IS_APPROVED],[DATE_APPROVED],[IS_HANDEDOVER],[DATE_HANDEDOVER],[DATE_START],[DATE_FINISH],[YEAR_OF_ORDER],[CLIENT_DETAILS],[SCOPE_OF_WORK],[IS_PROPOSAL],[PRJ_MANAGER],[PRJ_NAME],[MANAGER_VALDEL],[MANAGER_CLIENT],[DEPT_ID],[locationid],[cut_off_date]) SELECT * FROM  [pms].[Common].[PROJECT]  T WHERE T.PRJ_ID =  (@prj_id) SET IDENTITY_INSERT [PMS_BACKUP].[Common].[PROJECT] OFF        IF @@ERROR <> 0 GOTO HANDLE_ERROR
      SET IDENTITY_INSERT [PMS_BACKUP].[Common].[DEPARTMENT_CAP] ON  INSERT INTO [PMS_BACKUP].[Common].[DEPARTMENT_CAP] ([CAP_ID],[DEPT_ID],[PRJ_ID],[IS_CAPPED],[DATE_CAPPED],[CAPPED_BY],[CAP_APPROVED_BY],[STATUS],[UNCAPPED_BY],[DATE_UNCAPPED],[DESCRIPTION],[UNCAP_APPROVED_BY],[LOCATIONID]) SELECT * FROM  [pms].[Common].[DEPARTMENT_CAP]  T WHERE T.PRJ_ID =  (@prj_id) SET IDENTITY_INSERT [PMS_BACKUP].[Common].[DEPARTMENT_CAP] OFF        IF @@ERROR <> 0 GOTO HANDLE_ERROR
       INSERT INTO [PMS_BACKUP].[Common].[DOC_REG]  SELECT * FROM  [pms].[Common].[DOC_REG]  T WHERE T.PRJ_ID =  (@prj_id)    IF @@ERROR <> 0 GOTO HANDLE_ERROR 



    -- 3. Commit transaction

     COMMIT TRANSACTION @TranName;

        return @@trancount;

    HANDLE_ERROR: 
     rollback transaction @TranName
     RETURN 1 
    END

并且问题是即使第一个插入查询失败,它也不会停止处理并恢复其余的插入查询。我得到的返回值是1,但在结果窗口中我可以看到这样的日志

  

(0行(s)受影响)Msg 2627,等级   14,状态1,程序   sp_ProjectBackup_Insert,第35行   违反PRIMARY KEY约束   'PK_PROJECT'。无法插入重复   键入对象'Common.PROJECT'。该   声明已被终止。

     

(0行(s)受影响)

     

(0行(s)受影响)

我认为return 1将退出错误处理代码但不会发生。我的错误处理有问题吗?

2 个答案:

答案 0 :(得分:2)

这有很多问题,我不知道从哪里开始。

就错误调用而言,您正在捕获错误之前的最后一步运行是否存在错误,而不是到目前为止是否发生错误。由于最后一步不是insert而是set_identity_insert语句,因此没有错误要捕获。

现在,除此之外还有什么需要修复。

如果这是一个备份表并且仅用作备份表,请一起删除identity属性。无需继续打开和关闭插件,只需修复表,它不是由用户直接写入数据是来自另一个表的alawys,为什么它需要一个标识呢?

接下来,您收到的错误向我表明您需要做的是仅插入备份表中尚不存在的记录而不是所有记录。您可能还需要更新现有记录。或者,如果您只需要最新的数据周期并且复制的数据表不是那么大,那么您需要在执行插入之前先截断表(当只有100个是新的时,您不想重新输入百万条记录10个被改变了)。

在SQL Server 2005中,您可以使用TRY CATCH块,您应该开始使用它们而不是goto。

永远不要在插入中使用SELECT *。或者代码转到生产的任何时候。选择*是一种非常糟糕的编程技术。例如,在插入时,当您定义要插入的列而不是select中的列时,更改初始表时会导致问题。

最后,您不应该在开头用sp命名存储过程。系统procs以sp开头,SQL Server会先查看proc,然后再查看用户procs。每次调用proc都会浪费一点时间。总的来说,这对系统来说是不好的,如果它们碰巧有一个同名的系统proc,你的系统将永远不会被调用。

答案 1 :(得分:0)

您需要对语句进行适当的错误处理。使用SQL 2005及更高版本,这意味着尝试/ catch:

PROCEDURE [dbo].[sp_ProjectBackup_Insert] 
    @prj_id bigint 
    AS 
    BEGIN 
     DECLARE @MSG varchar(200) 
     DECLARE @TranName varchar(200) 
     DECLARE @return_value int 


    -- 1. Starting the transaction  
    BEGIN TRANSACTION @TranName 

    -- 2. Insert the records 

    BEGIN TRY

         SET IDENTITY_INSERT [PMS_BACKUP].[Common].[PROJECT] ON  INSERT INTO [PMS_BACKUP].[Common].[PROJECT] ([PRJ_ID],[PRJ_NO1],[PRJ_NO2],[PRJ_NO3],[PRJ_DESC],[IS_TASKFORCE],[DATE_CREATED],[IS_APPROVED],[DATE_APPROVED],[IS_HANDEDOVER],[DATE_HANDEDOVER],[DATE_START],[DATE_FINISH],[YEAR_OF_ORDER],[CLIENT_DETAILS],[SCOPE_OF_WORK],[IS_PROPOSAL],[PRJ_MANAGER],[PRJ_NAME],[MANAGER_VALDEL],[MANAGER_CLIENT],[DEPT_ID],[locationid],[cut_off_date]) SELECT * FROM  [pms].[Common].[PROJECT]  T WHERE T.PRJ_ID =  (@prj_id) SET IDENTITY_INSERT [PMS_BACKUP].[Common].[PROJECT] OFF        IF @@ERROR <> 0 GOTO HANDLE_ERROR 
         SET IDENTITY_INSERT [PMS_BACKUP].[Common].[DEPARTMENT_CAP] ON  INSERT INTO [PMS_BACKUP].[Common].[DEPARTMENT_CAP] ([CAP_ID],[DEPT_ID],[PRJ_ID],[IS_CAPPED],[DATE_CAPPED],[CAPPED_BY],[CAP_APPROVED_BY],[STATUS],[UNCAPPED_BY],[DATE_UNCAPPED],[DESCRIPTION],[UNCAP_APPROVED_BY],[LOCATIONID]) SELECT * FROM  [pms].[Common].[DEPARTMENT_CAP]  T WHERE T.PRJ_ID =  (@prj_id) SET IDENTITY_INSERT [PMS_BACKUP].[Common].[DEPARTMENT_CAP] OFF        IF @@ERROR <> 0 GOTO HANDLE_ERROR 
           INSERT INTO [PMS_BACKUP].[Common].[DOC_REG]  SELECT * FROM  [pms].[Common].[DOC_REG]  T WHERE T.PRJ_ID =  (@prj_id)    IF @@ERROR <> 0 GOTO HANDLE_ERROR  

        -- 3. Commit transaction 

        COMMIT TRANSACTION @TranName; 
        RETURN 0

    END TRY 

    BEGIN CATCH

        --HANDLE_ERROR
        ROLLBACK TRANSACTION @TranName 
        RETURN 1  

    END CATCH 

    END 

(一定要测试和调试 - 应该很好,但你永远不会知道。)

RETURN值仅与调用过程的任何内容相关 - 如果它没有检查成功或失败,那么您可能会遇到问题。