SQL Server-après insérer trigger-mettre à jour une autre colonne dans la même table

j'ai ce déclencheur de base de données:

CREATE TRIGGER setDescToUpper
ON part_numbers
 AFTER INSERT,UPDATE
AS
DECLARE @PnumPkid int, @PDesc nvarchar(128)

SET @PnumPkid = (SELECT pnum_pkid FROM inserted)
SET @PDesc = (SELECT UPPER(part_description) FROM inserted)

UPDATE part_numbers set part_description_upper = @PDesc WHERE pnum_pkid=@PnumPkid

GO

Est-ce une mauvaise idée? C'est pour mettre à jour une colonne sur la même table. Je veux qu'il démarre pour insérer et mettre à jour.

ça marche, j'ai juste peur d'une situation cyclique. La mise à jour, à l'intérieur de la gâchette, déclenche la gâchette, et encore et encore. Est-ce que ça arrivera?

s'il vous Plaît, ne pas pinailler sur les majuscules chose. Fou de la situation.

21
demandé sur marc_s 2011-03-17 18:53:11

7 réponses

cela dépend du niveau de récursion pour les triggers actuellement mis sur le DB.

Si tu fais ceci:

SP_CONFIGURE 'nested_triggers',0
GO
RECONFIGURE
GO

Ou:

ALTER DATABASE db_name
SET RECURSIVE_TRIGGERS OFF

cette gâchette ci-dessus ne sera pas appelée de nouveau, et vous seriez en sécurité (à moins que vous entriez dans une sorte d'impasse; cela pourrait être possible, mais peut-être que je me trompe).

Encore, J' ne pas pense que c'est une bonne idée. Une meilleure option serait d'utiliser un au lieu de trigger. De cette façon, vous évitez d'exécuter la première mise à jour (manuelle) sur le DB. Seul celui défini à l'intérieur du déclencheur serait exécuté.

An au lieu D'insérer trigger serait comme ceci:

CREATE TRIGGER setDescToUpper ON part_numbers
INSTEAD OF INSERT
AS
BEGIN
    INSERT INTO part_numbers (
        colA,
        colB,
        part_description
    ) SELECT
        colA,
        colB,
        UPPER(part_description)
    ) FROM
        INSERTED
END
GO

ceci "remplacerait" automatiquement la déclaration INSERT originale par celle-ci, avec un appel supérieur explicite appliqué à la part_description champ.

un déclencheur au lieu de UPDATE serait similaire (et je ne vous conseille pas de créer un seul déclencheur, gardez-les séparer.)

en outre, ceci adresse le commentaire @Martin: il fonctionne pour les inserts/mises à jour multirow (votre exemple ne fonctionne pas).

37
répondu rsenna 2012-10-22 21:06:14

une autre option serait d'inclure la déclaration update dans une déclaration IF et d'appeler TRIGGER_NESTLEVEL () pour restreindre la mise à jour étant lancée une deuxième fois.

CREATE TRIGGER Table_A_Update ON Table_A AFTER UPDATE 
AS
IF ((SELECT TRIGGER_NESTLEVEL()) < 2)
BEGIN
    UPDATE a
    SET Date_Column = GETDATE()
    FROM Table_A a
    JOIN inserted i ON a.ID = i.ID
END

lorsque le trigger tourne initialement, le TRIGGER_NESTLEVEL est défini à 1, de sorte que la déclaration de mise à jour sera exécutée. Cette déclaration de mise à jour déclenchera à son tour le même déclencheur sauf que cette fois le TRIGGER_NESTLEVEL est défini à 2 et la déclaration de mise à jour ne sera pas exécutée.

Vous pourriez vérifiez également le niveau TRIGGER_NESTLEVEL en premier et si son supérieur à 1 alors appeler RETURN to exit out of the trigger.

IF ((SELECT TRIGGER_NESTLEVEL()) > 1) RETURN;
13
répondu Jorriss 2011-12-17 05:19:10

Utilisez une colonne calculée à la place. Il est presque toujours préférable d'utiliser une colonne calculée qu'un déclencheur.

voir L'exemple ci-dessous d'une colonne calculée en utilisant la fonction supérieure:

create table #temp (test varchar (10), test2 AS upper(test))
insert #temp (test)
values ('test')
select * from #temp

et ne pas avoir l'air d'un disque rayé, mais c'est très important. Ne jamais écrire un déclencheur qui ne fonctionnera pas correctement sur les inserts/mises à jour/suppressions d'enregistrements multiples. Il s'agit d'une pratique extrêmement mauvaise, car tôt ou tard l'une d'elles se produira et votre trigger causera des problèmes d'intégrité des données, car il n'échouera pas précisément, il ne lancera le processus que sur l'un des enregistrements. Cela peut durer longtemps jusqu'à ce que quelqu'un découvre le désordre et par themn il est souvent impossible de corriger correctement les données.

6
répondu HLGEM 2011-03-17 17:10:04

Oui, il récursive appelez votre détente, à moins que vous tournez le récursive déclencheurs de la mise hors tension:

ALTER DATABASE db_name SET RECURSIVE_TRIGGERS OFF 

MSDN a une bonne explication du comportement à http://msdn.microsoft.com/en-us/library/aa258254 (SQL.80).aspx sous la rubrique des déclencheurs récursifs.

1
répondu Paul Kearney - pk 2011-03-17 16:05:19

Oui...avoir une étape supplémentaire pour mettre à jour une table dans laquelle vous pouvez définir la valeur dans l'insertion numérique est probablement un processus supplémentaire, évitable. Avez-vous accès à la déclaration insert originale où vous pouvez simplement insérer la part_description dans la colonne part_description_upper en utilisant la valeur supérieure(part_description)?

après réflexion, vous n'avez probablement pas accès car vous l'auriez probablement fait, donc vous devriez aussi donner quelques options comme bien...

1) dépend de la nécessité de cette colonne part_description_upper, si juste pour " visualiser "puis peut utiliser la valeur de part_description retournée et" ToUpper () " elle (en fonction du langage de programmation).

2) Si vous voulez éviter le traitement "en temps réel", vous pouvez simplement créer une tâche sql pour passer en revue vos valeurs Une fois par jour pendant les périodes de faible trafic et mettre à jour cette colonne vers la partie supérieure de la valeur part_description pour celles qui ne sont pas actuellement définies.

3) suivre votre déclencheur (et de regarder pour la récursivité comme d'autres l'ont mentionné)...

HTH

Dave

1
répondu Dave 2011-03-17 16:11:29

Il pourrait être plus sûr de quitter le déclencheur quand il n'y a rien à faire. Vérifier le niveau imbriqué ou modifier la base de données en éteignant récursive peut être sujet à des problèmes.

Ms sql fournit un moyen simple, dans un trigger, pour voir si des colonnes spécifiques ont été mises à jour. Utilisez la méthode UPDATE () pour voir si certaines colonnes ont été mises à jour, comme UPDATE (part_description_upper).

IF UPDATE(part_description_upper)
  return
1
répondu Visual Micro 2015-02-04 17:05:52
create or replace 
TRIGGER triggername BEFORE INSERT  ON 
table FOR EACH ROW 
BEGIN
/*
Write any select condition if you want to get the data from other tables
*/
:NEW.COLUMNA:= UPPER(COLUMNA); 
--:NEW.COUMNa:= NULL;
END; 

le déclencheur ci-dessus va mettre à jour la valeur de la colonne avant de l'insérer. Par exemple, si nous donnons la valeur de COLUMNA comme null, il mettra à jour la colonne comme null pour chaque instruction insert.

-3
répondu user2746639 2013-09-04 11:25:08