Процедура возобновляется даже после ошибки - PullRequest
0 голосов
/ 29 июля 2010

Ниже приведена моя процедура в 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 строк) Сообщение 2627, Уровень 14, Состояние 1, Процедура sp_ProjectBackup_InsertСтрока 35 Нарушение ограничения PRIMARY KEY 'PK_PROJECT'.Невозможно вставить повторяющийся ключ в объект Common.PROJECT.Оператор был прерван.

(затронуто 0 строк)

(затронуто 0 строк)

Я думал, что return 1 будетсделать выход из кода обработки ошибок, но не происходит.Любая проблема с моей обработкой ошибок?

Ответы [ 2 ]

2 голосов
/ 29 июля 2010

В этом столько всего плохого, что я не знаю, с чего начать.

Что касается вашего вызова с ошибкой, вы отслеживаете, есть ли ошибка на последнем шаге, выполненном перед ошибкой, а не если какая-либо ошибка произошла до сих пор. Поскольку последний шаг - это не вставка, а оператор set_identity_insert, нет ошибки для перехвата.

Теперь о том, что нужно исправить, кроме этого.

Если это таблица резервных копий и используется только как таблица резервных копий, все вместе избавьтесь от свойства удостоверения. Нет необходимости постоянно включать и выключать вставку, просто исправьте таблицу, она не записывается пользователями напрямую, а данные поступают из другой таблицы, так зачем вообще нужна идентификация?

Далее, ошибка, которую вы получили, указывает мне, что вам нужно вставить только те записи, которые еще не существуют, в таблицу резервных копий, а не все записи. Вам также может понадобиться обновить существующие записи. Или вам нужно сначала обрезать таблицу перед выполнением вставки, если вам нужен только самый последний период данных, а копируемая таблица данных не такая большая (вы не хотите повторно вводить миллион записей, когда только 100 были новыми и 10 были изменены).

В SQL Server 2005 у вас есть доступные блоки TRY CATCH, вы должны начать использовать их вместо goto.

Никогда, никогда, никогда не используйте SELECT * во вставке. Или в любое время код будет запущен в производство. Select * - очень плохая методика программирования. Например, при вставке это вызовет проблемы при изменении исходной таблицы, поскольку вы определяете столбцы для вставки, но не столбцы для выбора.

Наконец, вы не должны называть хранимые процедуры с sp в начале. Системные процессы запускаются с sp, и SQL Server сначала будет искать процедуру, прежде чем просматривать пользовательские процедуры. Это немного потерянное время каждый раз, когда вы вызываете прок. В целом, это плохо для системы, и если у них будет системный процесс с таким же именем, ваш никогда не будет вызван.

0 голосов
/ 29 июля 2010

Вам необходимо правильно обработать ошибки вокруг ваших утверждений. С SQL 2005 и выше это означает try / 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 относится только к тому, что называется процедурой - если она не проверяет успех или неудачу, у вас может быть проблема.

...