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.
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).
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;
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.
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.
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
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
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.