2012-03-23 1 views
0

트랜잭션이 항상 실패하여 저장 프로 시저에 문제가 있습니다. 나는 그것이 IF EXISTS(SELECT 1 FROM TargetTable WHERE BaseTableId = @BaseTableId) 또는 그 주위의 코드가 구조화 된 방법이라고 생각하지만 트랜잭션이 항상 실패하지 않도록 스토어드 프로 시저를 수정하는 방법을 모르겠습니다. 모든 트랜잭션 코드를 제거하고 저장 프로 시저에서 트랜잭션없이 동일한 작업을 수행하면 작동합니다. 모든 업데이트 및/또는 삽입이 성공합니다.이 SQL Server 트랜잭션이 항상 실패하고 저장 프로 시저 구조를 수정하는 방법은 무엇입니까?

CREATE PROCEDURE [dbo].[proc_BaseTable_TargetTable_Update] 
(
@BaseTableId  bigint, 
@BaseTableTypeId  bigint, 
@Alias  nvarchar(max), 
@TargetTableNonPkItemId bigint, 
@OtherField  nvarchar(max) = NULL 
) 
AS 
-- NOTE: There is a problem with enabling tractions on this, the trans always fails 
-- with the current structure, seemingly because of the SELECT 1 FROM TARGETTABLE 
BEGIN 
BEGIN TRAN 

    UPDATE BaseTable 
     SET 
      Alias = @Alias, 
      BaseTableTypeId = @BaseTableTypeId, 
      UpdatedOn = GETUTCDATE() 
    WHERE BaseTableId = @BaseTableId 

    IF @@ERROR <> 0 
    BEGIN 
     RAISERROR('Error updating BaseTable', 16, 1) 
     ROLLBACK TRAN 
     RETURN 
    END 

    IF EXISTS(SELECT 1 FROM TargetTable WHERE BaseTableId = @BaseTableId) 
     UPDATE TargetTable 
      SET 
       TargetTableNonPkItemId = @TargetTableNonPkItemId, 
       OtherField = @OtherField 
     WHERE BaseTableId = @BaseTableId 

     IF @@ERROR <> 0 
     BEGIN 
      RAISERROR('Error updating TargetTable', 16, 1) 
      ROLLBACK TRAN 
      RETURN 
     END 
    ELSE 
     INSERT INTO TargetTable(BaseTableId, TargetTableNonPkItemId, OtherField) 
     VALUES (@BaseTableId, @TargetTableNonPkItemId, @OtherField) 

     IF @@ERROR <> 0 
     BEGIN 
      RAISERROR('Error inserting TargetTable', 16, 1) 
      ROLLBACK TRAN 
      RETURN 
     END 

COMMIT TRAN 
END 

답변

3

IF을 포장해야합니다.

CREATE PROCEDURE [dbo].[proc_BaseTable_TargetTable_Update] 
(
@BaseTableId  bigint, 
@BaseTableTypeId  bigint, 
@Alias  nvarchar(max), 
@TargetTableNonPkItemId bigint, 
@OtherField  nvarchar(max) = NULL 
) 
AS 
-- NOTE: There is a problem with enabling tractions on this, the trans always fails 
-- with the current structure, seemingly because of the SELECT 1 FROM TARGETTABLE 
BEGIN 
BEGIN TRAN 

    UPDATE BaseTable 
     SET 
      Alias = @Alias, 
      BaseTableTypeId = @BaseTableTypeId, 
      UpdatedOn = GETUTCDATE() 
    WHERE BaseTableId = @BaseTableId 

    IF @@ERROR <> 0 
    BEGIN 
     RAISERROR('Error updating BaseTable', 16, 1) 
     ROLLBACK TRAN 
     RETURN 
    END 

    IF EXISTS(SELECT 1 FROM TargetTable WHERE BaseTableId = @BaseTableId) 
    BEGIN 
     UPDATE TargetTable 
      SET 
       TargetTableNonPkItemId = @TargetTableNonPkItemId, 
       OtherField = @OtherField 
     WHERE BaseTableId = @BaseTableId 

     IF @@ERROR <> 0 
     BEGIN 
      RAISERROR('Error updating TargetTable', 16, 1) 
      ROLLBACK TRAN 
      RETURN 
     END 
    END 
    ELSE 
    BEGIN 
     INSERT INTO TargetTable(BaseTableId, TargetTableNonPkItemId, OtherField) 
     VALUES (@BaseTableId, @TargetTableNonPkItemId, @OtherField) 

     IF @@ERROR <> 0 
     BEGIN 
      RAISERROR('Error inserting TargetTable', 16, 1) 
      ROLLBACK TRAN 
      RETURN 
     END 
    END 

COMMIT TRAN 
END 
: 어떤 코드에서 일어나고있는 것은이

IF EXISTS 
{ 
    UPDATE 
    RAISE ERROR IF BAD 
} 
ELSE 
{ 
    INSERT 
    RAISE ERROR IF BAD 
} 

같은 것을 기대하지만, 대신 그래서이

IF EXISTS 
    UPDATE 


IF ERROR 
    RAISE ERROR 
ELSE 
    INSERT 


IF ERROR 
    RAISE ERROR 

로 끝날 것입니다, 여기에 코드가 어떻게 보일지입니다

2

당신은 당신이 그 블록에 여러 개의 문을 가지고 있기 때문에 IF 후와 ELSE 후 BEGIN/END 블록을 추가해야합니다.

+2

I alawys은 시작 끝을 작성하거나하지, 그것은 쉽게 유지 보수를하고 실수를 방지 할 수 있으며 의도가 명확합니다. – HLGEM

1

오류 처리를 위해 TRY CATCH를 사용하는 것을 선호합니다. 아래 예제는보다 유용한 오류 메시지를 제공합니다. 내가 하나의 문장이 있는지 여부를

CREATE PROCEDURE [dbo].[proc_BaseTable_TargetTable_Update] 
(@BaseTableId  bigint 
, @BaseTableTypeId  bigint 
, @Alias  nvarchar(max) 
, @TargetTableNonPkItemId bigint 
, @OtherField  nvarchar(max) = NULL) 
AS 

BEGIN TRY 
BEGIN TRAN  
    UPDATE BaseTable   
    SET Alias = @Alias 
    , BaseTableTypeId = @BaseTableTypeId 
    , UpdatedOn = GETUTCDATE()  
    WHERE BaseTableId = @BaseTableId   

IF EXISTS(SELECT 1 FROM TargetTable WHERE BaseTableId = @BaseTableId)   
    UPDATE TargetTable    
    SET TargetTableNonPkItemId = @TargetTableNonPkItemId 
     , OtherField = @OtherField   
    WHERE BaseTableId = @BaseTableId   
ELSE   
    INSERT INTO TargetTable(BaseTableId, TargetTableNonPkItemId, OtherField)   
    VALUES (@BaseTableId, @TargetTableNonPkItemId, @OtherField) 

IF @@TRANCOUNT > 0 
    BEGIN 
     COMMIT TRAN 
    END 
END TRY 

BEGIN CATCH 

    SELECT 
      ERROR_NUMBER() AS ErrorNumber 
      ,ERROR_SEVERITY() AS ErrorSeverity 
      ,ERROR_STATE() AS ErrorState 
      ,ERROR_PROCEDURE() AS ErrorProcedure 
      ,ERROR_LINE() AS ErrorLine 
      ,ERROR_MESSAGE() AS ErrorMessage; 

IF @@TRANCOUNT > 0 
    BEGIN 
     ROLLBACK TRAN 
    END 

END CATCH 
+0

도움을 주셔서 감사합니다. 이게 내 문제를 해결했습니다! – jon333