2016-10-28 1 views
0

J'ai une table 'TEST' avec quelques colonnes. Colonnes de VALIDÉS 'et 'DELETED' sont des valeurs bitRestauration à l'intérieur du déclencheur pour une ligne lorsque plusieurs lignes sont insérées

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

Id est une valeur INT et la clé primaire.

J'ai créé ci-dessous déclencheur pour cette table et la colonne « SUPPRIME » seulement quand il est mis à jour:

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 

Maintenant, j'effectuer ci-dessous la déclaration de mise à jour:

Update TEST 
SET DELETED=1 

Au-dessus de déclenchement éviter de marquer comme supprimé une ligne déjà validée. Lorsqu'une ligne est validée et que j'essaie de la marquer comme supprimée, une restauration est effectuée.

Mon doute est: Est-ce que Roolback est fait pour toutes les lignes mises à jour? ou est rollback fait pour seulement la rangée en cours de traitement.

Comment est-ce que je peux faire le rollback seulement pour la rangée qui soulève l'erreur et commet le repos?

+0

Vous avez 3 variables dans le déclencheur ci-dessus, Id, Process_ID et Process. Donc, je ne suis pas sûr si ce déclencheur fonctionne même. –

+1

Vous n'avez pas besoin d'un curseur ici. Vous pouvez le faire en tant que requête basée sur un ensemble sans aucun problème. Et une annulation annule la transaction ENTIER, pas une seule ligne. Déclenche le déclenchement du serveur sql une fois par opération. –

+0

@WEI_DBA Correct. Je l'ai corrigé. C'était une erreur en tapant. Pardon. – user1624552

Répondre

3

Débarrassez-vous de ce curseur. Il ne fait rien d'autre que de le rendre plus lent et plus compliqué qu'il ne devrait l'être. Vous n'avez pas besoin de vérifier chaque ligne, vous avez seulement besoin de voir s'il y a une ligne en cours de mise à jour qui viole votre règle métier.

Votre déclencheur entier peut être réduit à ceci.

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