2012-03-23 5 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をラップする必要があります。どのようなあなたのコード内で起こっていることは、あなたがこの

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 

で終わる、ここにあなたのコードがどのように見えるかです:

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 
2

これらのブロックに複数のステートメントがあるため、IFの後とELSEの後にBEGIN/ENDブロックを追加する必要があります。

+2

私は1つのステートメントを持っているかどうかにかかわらず、メンテナンスを行う際のミスを避けやすく、意図を明確にします。 – 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

関連する問題