Triggers SQL - supprimés ou mis à jour? ou peut-être autre chose?
-
26-10-2019 - |
Question
Je suis en train de comprendre que je dois utiliser ici. Supprimé, inséré ou mis à jour
essentiellement.
Je dois écrire des données à la table de l'histoire, lorsque la table principale est mis à jour, et que si les changements d'état de quelque chose soit en attente ou actif.
Voici ce que j'ai maintenant:
ALTER TRIGGER [dbo].[trg_SourceHistory] ON [dbo].[tblSource]
FOR UPDATE AS
DECLARE @statusOldValue char(1)
DECLARE @statusNewValue char(1)
SELECT @statusOldValue = statusCode FROM deleted
SELECT @statusNewValue= statusCode FROM updated
IF (@statusOldValue <> @statusNewValue) AND
(@statusOldValue = 'P' or @statusOldValue = 'A')
BEGIN TRY
INSERT * INTO tblHistoryTable)
select * from [DELETED]
donc je veux que les nouvelles données pour rester dans le tableau principal, le tableau de l'histoire à être mis à jour avec ce qui est ... écrasé en ce moment il se contente de recopier les mêmes informations sur. donc après la mise à jour, mes deux tables ont les mêmes données.
La solution
Vous devez utiliser à la fois les tables de inserted
et deleted
ensemble pour vérifier les dossiers que:
1. existait déjà (pour vérifier ce n'est pas un insert)
2. existe toujours (pour vérifier ce n'est pas une suppression)
3. Le champ d'état a changé
Vous devez également vous assurer que vous le faites dans une approche définie, selon la réponse de marc_s, les déclencheurs ne sont pas des processus d'enregistrement unique.
INSERT INTO
tblHistoryTable
SELECT
deleted.*
FROM
inserted
INNER JOIN
deleted
ON inserted.PrimaryKey = deleted.PrimaryKey
WHERE
inserted.StatusCode <> deleted.StatusCode
AND (inserted.StatusCode = 'P' OR inserted.StatusCode = 'A')
- = insérer les nouvelles valeurs
- deleted = les anciennes valeurs
Autres conseils
Il n'y a que les tables pseudo Inserted
et Deleted
- il n'y a pas Updated
.
Pour un UPDATE
, Inserted
contient les nouvelles valeurs (après la mise à jour), tandis que Deleted
contient les anciennes valeurs avant la mise à jour.
Aussi sachez que les déclencheurs est tiré une fois par lot - pas une seule fois pour chaque ligne. Ainsi, les deux tables de pseudo contiennent potentiellement plusieurs lignes ! Ne présumez pas seulement une seule ligne et assigner à une variable - ce
SELECT @statusOldValue = statusCode FROM deleted
SELECT @statusNewValue= statusCode FROM updated
échouera si vous avez plusieurs lignes! Vous devez écrire vos déclencheurs de telle façon qu'ils travaillent avec plusieurs lignes dans Inserted
et Deleted
!
Mise à jour: oui - il IS une bien meilleure façon d'écrire ceci:
ALTER TRIGGER [dbo].[trg_SourceHistory] ON [dbo].[tblSource]
FOR UPDATE
AS
INSERT INTO dbo.tblHistoryTable(Col1, Col2, Col3, ...., ColN)
SELECT Col1, COl2, Col3, ..... ColN
FROM Deleted d
INNER JOIN Inserted i ON i.PrimaryKey = d.PrimaryKey
WHERE i.statusCode <> d.statusCode
AND d.statusCode IN ('A', 'P')
En gros:
-
spécifier explicitement les colonnes que vous souhaitez insérer - tant dans la déclaration de
INSERT
ainsi que la déclaration deSELECT
récupérer les données à insérer - pour éviter les mauvaises surprises -
créer une
INNER JOIN
entre les tables pseudo-Inserted
etDeleted
pour obtenir toutes les lignes qui ont été mis à jour -
toutes les autres conditions préciser (différents codes d'état, etc.) dans la clause
WHERE
duSELECT
Cette solution fonctionne pour les lots de lignes étant mis à jour - il ne manquera pas sur une mise à jour à plusieurs rangs ....
Il n'y a pas de table de updated
, vous cherchez inserted
.