Pourquoi FOR Trigger ne s'exécute pas avant l'action?
-
03-07-2019 - |
Question
J'essaie d'écrire un déclencheur sur une table pour éviter l'insertion de deux noms qui ne sont pas marqués comme IsDeleted. Mais la première partie de la sélection contient celle qui a été insérée et la condition est donc toujours vraie. Je pensais qu'en utilisant le mot-clé FOR, le déclencheur s'exécutait avant l'INSERTION, mais dans ce cas, la ligne insérée est déjà dans la table. Est-ce que je me trompe ou que c'est ainsi que fonctionnent tous les déclencheurs POUR?
ALTER TRIGGER TriggerName
ON MyTable
FOR INSERT, UPDATE
AS
BEGIN
If exist (select [Name] From MyTable WHERE IsDeleted = 0 AND [Name] in (SELECT [Name] FROM INSERTED)
BEGIN
RAISERROR ('ERROR Description', 16, 1);
Rollback;
END
END
La solution
FOR s'exécute après la modification des données. INSTEAD OF est ce que je pense que vous recherchez.
EDIT: comme d'autres l'ont indiqué, INSTEAD OF est exécuté à la place des données que vous modifiez. Vous devez donc insérer les données si elles sont valides, plutôt que d'arrêter l'insertion si elles sont invalides.
Lisez cette question pour une explication beaucoup plus détaillée des types de déclencheurs.
SQL Server " AFTER INSERT " le déclencheur ne voit pas la ligne qui vient d'être insérée
Autres conseils
FOR est identique à APRÈS. si vous voulez "simuler" AVANT le déclenchement, utilisez INSTEAD OF, caveat, ce n’est pas exactement ce que vous attendez du bon déclencheur, c’est-à-dire que si vous ne fournissez pas l’action INSTEAD nécessaire, vos données insérées / mises à jour pourraient être perdues / ignorées.
MSSQL n’a pas de déclencheur AVANT.
Pour SQL Server, FOR s'exécute APRÈS le SQL qui l'a déclenché.
De: http://msdn.microsoft.com/en-us/library/ms189799. aspx
POUR | APRÈS
APRES indique que le déclencheur DML est renvoyé uniquement lorsque toutes les opérations spécifié dans le SQL de déclenchement déclaration ont été exécutés avec succès. Toutes les actions en cascade référentielles et les contrôles de contrainte doivent également réussir avant que ce déclencheur ne se déclenche.
APRES est la valeur par défaut lorsque FOR est le seul mot clé spécifié.
APRES des déclencheurs ne peut pas être défini dans les vues.
En fait, j’ai rencontré un problème similaire récemment et j’ai trouvé un moyen intéressant de le gérer. J'avais une table qui pouvait avoir plusieurs lignes pour un même identifiant, mais une seule d'entre elles pouvait être marquée comme primaire.
Dans SQL Server 2008, vous pourrez créer un index unique partiel, comme suit:
create unique index IX on MyTable(name) where isDeleted = 0;
Cependant, vous pouvez accomplir cela avec un peu plus de travail dans SQL Server 2005. L'astuce consiste à créer une vue affichant uniquement les lignes non supprimées, puis à créer un index en cluster unique:
create view MyTableNotDeleted_vw
with schema_binding /* Must be schema bound to create an indexed view */
as
select name
from dbo.MyTable /* Have to use dbo. for schema bound views */
where isDeleted = 0;
GO
create unique clustered index IX on MyTableNotDeleted_vw ( name );
Ceci créera effectivement une contrainte unique affectant uniquement les lignes qui n'ont pas encore été supprimées et fonctionnera probablement mieux qu'un déclencheur personnalisé!