11
votes

SQL Server Un déclencheur pour fonctionner sur plusieurs inserts de rangée

Je maintient du code qui a une gâchette sur une table pour incrémenter une colonne. Cette colonne est ensuite utilisée par une application tierce a . Disons que la table s'appelle test avec deux colonnes num1 et num2 . La gâchette fonctionne sur chaque insertion de num1 dans test . Voici la gâchette: xxx

Cela fonctionne bien dans des inserts simples à base de lignes, mais il existe une autre application de 3ème partie b (soupir) qui fait parfois plusieurs insertions à ce sujet. Table de quelque chose comme ça, mais pas exactement: xxx

Ceci provoque une capacité de se comporter de manière erratique ...

Maintenant, je n'ai pas accès à la source de l'application a ou b et contrôlez uniquement la base de données et la gâchette. Y a-t-il quelque chose qui peut être fait avec la gâchette de sorte que les mises à jour effectuées pour num2 sont correctes en cas de multiples inserts?

solution:

Suivant est la solution basée sur le code de Affan: xxx

vérifier ici pour une approche définie: SQL Server - Réécrivez la gâchette pour éviter une approche basée sur le curseur


2 commentaires

Un curseur à l'intérieur d'un déclencheur est une horriblement mauvaise idée ; Les curseurs sont notoirement lents et des porcs de mémoire, et tout ce qui est dans un déclencheur devrait être aussi maigre et rapide que jamais humainement possible. Je voudrais fortement conseiller d'utiliser une approche différente (de ma propre expérience personnelle et angoissante avec de telles constructions)


Ne pouvait pas si @ newnum2 est null vérifier être remplacé par coalesce (max (num2), 0) ?


4 Réponses :


3
votes

Jetez un coup d'œil à inséré pseudo table dans votre déclencheur car il contiendra plusieurs rangées au cours de ces opérations. Vous devez toujours gérer plusieurs rangées dans vos déclencheurs de toute façon.

Voir ici pour plus d'informations:

Comment tester plusieurs Actions de ligne dans une gâchette SQL Server?


0 commentaires

2
votes

La gâchette doit être réécrite pour gérer plusieurs inserts de rangée. Ne jamais écrire un déclencheur comme ça à l'aide de variables. Tous les déclencheurs doivent considérer qu'AlaWys considère que quelqu'un quelqu'un va faire une insertion / mise à jour / suppression de plusieurs lignes.

Vous ne devriez pas incrémenter des colonnes de cette manière dans une gâchette non plus, si vous avez besoin de numéros de colonne incrémentés, pourquoi n'utilisez-vous pas une colonne d'identité?


1 commentaires

Je n'ai pas aimé la façon dont les colonnes étaient incrémentées non plus et j'ai même modifié la gâchette à Oracle pour utiliser une séquence. En ce qui concerne l'identité, ma première pensée était d'utiliser Alter Table pour la modifier à une identité, mais malheureusement, cela n'est pas possible et d'autres moyens de le faire nécessiter davantage de changements que je suis suffisamment courageux pour les dangers.



5
votes

Il vous suffit d'ouvrir un curseur sur inséré et de l'itération pour @ proc_newnum1 et mettez votre reste de code que la boucle. e.g xxx


3 commentaires

Bien que ce qui précède ne soit pas tout à fait correct et que certaines erreurs, cela m'a aidé en me donnant une base pour travailler avec. J'ai ajouté la version mise à jour de ce qui précède dans ma question.


Je suis désolé, mais un curseur n'est pas le meilleur moyen de le faire.


@Cocowalla Vous faites un rejoindre entre la table insérée et la table de données de base. Pour obtenir des valeurs d'incrémentation pour la mise à jour, utilisez Row_Number () (SQL 2005 et UP) ou un insert sur une table TEMP avec une colonne d'identité ou une table de chiffres avec un million de lignes environ (ajoute uniquement 13 mégaoctets à la base de données). En fait, mieux que tout cela est de remplacer la colonne par une colonne d'identité qui donne déjà des valeurs incrémentées!



0
votes

Comme déjà signalé, les curseurs peuvent être problématiques et il est préférable d'utiliser des jointures entre la table déclenchée et les tables insérées et supprimées.

Voici un exemple de comment faire: P>

ALTER TRIGGER [dbo].[TR_assign_uuid_to_some_varchar_column]
ON [dbo].[myTable]
AFTER INSERT, UPDATE
AS
BEGIN
/********************************************
 APPROACH
  * we only care about update and insert in this case
  * for every row in the "inserted" table, assign a new uuid for blanks
*********************************************/

       update t 
              set uuid_as_varchar = lower(newid()) 
       from myTable t 

        -- inserted table is populated for row updates and new row inserts
       inner join inserted i on i.myPrimaryKey = t.myPrimarykey

        -- deleted table is populated for row updates and row deletes
       left join deleted d on d.myPrimaryKey = i.myPrimaryKey

        -- only update the triggered table for rows applicable to the trigger and
        -- the condition of currently having a blank or null stored for the id
       where 
           coalesce(i.uuid_as_varchar,'') = '' 

           -- you can also check the row being replaced as use that as part of the conditions, e.g. 
           or ( coalesce(i.uuid_as_varchar,'') <> coalesce(d.uuid_as_varchar,'') );
       
END


0 commentaires