插入多行时在触发器内回滚一行

Rollback within trigger for one row when multiple rows are in inserted

我有一个包含一些列的 table 'TEST'。 'VALIDATED' 和 'DELETED' 列是位值

 TEST Table:
    Id      VALIDATED     DELETED
     1           0          0
     2           0          0
     3           1          0
     4           0          0
     5           1          0
     6           0          0 

Id 是一个 INT 值和主键。

我仅在更新时为此 table 和列 'DELETED' 创建了以下触发器:

CREATE TRIGGER [dbo].[MY_TRIGGER]   
   ON  [dbo].[TEST] 
   FOR UPDATE 
AS 
IF UPDATE([DELETED])
BEGIN

DECLARE @Id INT;

DECLARE db_cursor CURSOR FOR
SELECT DISTINCT (I.Id)
FROM INSERTED I;

OPEN db_cursor   
FETCH NEXT FROM db_cursor INTO @Id

WHILE @@FETCH_STATUS = 0   
BEGIN  

    IF EXISTS(SELECT * FROM INSERTED WHERE Id = @Id AND VALIDATED = 1)
    BEGIN

        IF EXISTS (SELECT 
                     FROM DELETED D INNER JOIN INSERTED I
                       ON D.Id = I.Id
                    WHERE D.Id = @Id AND D.[DELETED] = 0 
                          AND I.[DELETED] = 1)

        BEGIN
            RAISERROR('CANNOT DELETE!' ,10, 1);
            ROLLBACK
        END
    END


   FETCH NEXT FROM db_cursor INTO @Id
END  

 CLOSE      db_cursor;
 DEALLOCATE db_cursor;
END

现在我执行以下更新语句:

Update TEST
SET    DELETED=1

以上触发器避免将已验证的行标记为已删除。 当一行被验证并且我试图将其标记为已删除时,回滚就完成了。

我的疑问是: 是否对所有更新的行进行了回滚?或者仅对正在处理的行进行回滚。

如何只回滚引发错误的行并提交其余行?

去掉那个光标。它什么也没做,只是让这个过程变得比它需要的更慢和更复杂。您不需要检查每一行,您只需要查看是否有违反您的业务规则的正在更新的行。

你的整个触发器可以减少到这个。

CREATE TRIGGER [dbo].[MY_TRIGGER]   
   ON  [dbo].[TEST] 
   FOR UPDATE 
AS 
    IF EXISTS 
    (
        SELECT *
        FROM DELETED D 
        INNER JOIN INSERTED I ON D.Id = I.Id
        WHERE D.[DELETED] = 0 
            AND I.[DELETED] = 1
    )
    BEGIN
        RAISERROR('CANNOT DELETE!' ,10, 1);
        ROLLBACK
    END