在非连续步骤上应用 sql 个事务

applying sql transactions on non consecutive steps

我有以下 SQL 语句的场景:

DELETE FROM T1
DELETE FROM T2
DELETE FROM T3
DELETE FROM T4
DELETE FROM T5

在上面的例子中我需要实现:

  1. 如果下一个SQL语句失败,将回滚前一个语句,如果成功,它将移动到下一个语句。

  2. 但是对于第5步,我需要回滚第3步,按原样提交第4步。

任何意见,请指教。

在SQL 服务器中没有嵌套事务这样的东西。但是您可以通过一些错误处理编排来做到这一点。

如果在 T5 命令上遇到错误,此示例代码只是再次从 T4 重新发出删除命令。

SET NOCOUNT ON;

-- (use temp table, since table vars do not participate in transactions)
CREATE TABLE #T1(C int);
CREATE TABLE #T2(C int);
CREATE TABLE #T3(C int);
CREATE TABLE #T4(C int);
CREATE TABLE #T5(C int);

INSERT INTO #T1 SELECT 1;
INSERT INTO #T2 SELECT 1;
INSERT INTO #T3 SELECT 1;
INSERT INTO #T4 SELECT 1;
INSERT INTO #T5 SELECT 1;

BEGIN TRY 

    BEGIN TRAN TR1;

    DELETE FROM #T1;
    DELETE FROM #T2;
    DELETE FROM #T3;    
    DELETE FROM #T4;
    --select 1/0 as 'forced error @ stage1';
END TRY
BEGIN CATCH
    PRINT 'error @stage1';
    PRINT 'rollback @stage1';

    ROLLBACK TRAN TR1;  
    RETURN;
END CATCH

BEGIN TRY
    DELETE FROM #T5;
    select 1/0 as 'forced error @stage2';
    COMMIT TRAN TR1;
END TRY
BEGIN CATCH
    PRINT 'error @stage2';  
    ROLLBACK TRAN TR1;  

    BEGIN TRY
        print 'redo delete T4'
        BEGIN TRAN TR2;
        DELETE FROM #t4;
        --select 1/0 as 'forced error @redo delete';
        COMMIT TRAN TR2;
    END TRY
    BEGIN CATCH
        ROLLBACK TRAN TR2;
        PRINT 'second chance delete from T4 failed';    
    END CATCH

END CATCH

select count(*) as count,'T1' as 'table' from #T1
union all
select count(*) as count,'T2' as 'table' from #T2
union all
select count(*) as count,'T3' as 'table' from #T3
union all
select count(*) as count,'T4' as 'table' from #T4
union all
select count(*) as count,'T5' as 'table' from #T5

DROP TABLE #T1;
DROP TABLE #T2;
DROP TABLE #T3;
DROP TABLE #T4;
DROP TABLE #T5;

您可以在 TRY-CATCH 块中使用 SAVE POINTSGOTO 来完成:

这可以实现您在问题中想要的两个目标:

每次取消注释特定的“SELECT 1/0”语句时对其进行测试:

SET NOCOUNT ON;

CREATE TABLE #T1(ID int);
CREATE TABLE #T2(ID int);
CREATE TABLE #T3(ID int);
CREATE TABLE #T4(ID int);
CREATE TABLE #T5(ID int);

INSERT INTO #T1 SELECT 1;
INSERT INTO #T2 SELECT 1;
INSERT INTO #T3 SELECT 1;
INSERT INTO #T4 SELECT 1;
INSERT INTO #T5 SELECT 1;

BEGIN TRAN 
        BEGIN TRY
            DELETE FROM #T1
            --SELECT 1/0
        END TRY
        BEGIN CATCH
            ROLLBACK TRAN
            GOTO LAST2
        END CATCH

    SAVE TRAN pice1
        BEGIN TRY
            DELETE FROM #T2
            --SELECT 1/0
        END TRY
        BEGIN CATCH
            ROLLBACK TRAN 
            GOTO LAST2
        END CATCH

    SAVE TRAN pice2
        BEGIN TRY
            DELETE FROM #T3
            --SELECT 1/0
        END TRY
        BEGIN CATCH
            ROLLBACK TRAN pice1
            GOTO LAST
        END CATCH

    SAVE TRAN pice3
        BEGIN TRY
            DELETE FROM #T4
            --SELECT 1/0
        END TRY
        BEGIN CATCH
            ROLLBACK TRAN pice2
            GOTO LAST
        END CATCH

    SAVE TRAN pice4
        BEGIN TRY
            DELETE FROM #T5
            SELECT 1/0
        END TRY
        BEGIN CATCH
            ROLLBACK TRAN pice2
            DELETE FROM #T4
            GOTO LAST
        END CATCH

LAST:
COMMIT TRAN
LAST2:
SELECT COUNT(*) CT,'T1' [TABLE] FROM #T1
UNION
SELECT COUNT(*) CT,'T2' [TABLE] FROM #T2
UNION
SELECT COUNT(*) CT,'T3' [TABLE] FROM #T3
UNION
SELECT COUNT(*) CT,'T4' [TABLE] FROM #T4
UNION
SELECT COUNT(*) CT,'T5' [TABLE] FROM #T5

DROP TABLE #T1;
DROP TABLE #T2;
DROP TABLE #T3;
DROP TABLE #T4;
DROP TABLE #T5;