Lors de la configuration d'une piste d'audit, je n'ai aucun problème à suivre qui met à jour ou insérer des enregistrements dans une table, cependant, suivre qui supprime les enregistrements semble plus problématique.
Je peux suivre les insertions / mises à jour en incluant dans l'insertion / mise à jour le champ "UpdatedBy". Cela permet au déclencheur INSERT / UPDATE d'avoir accès au champ "UpdatedBy" via inserted.UpdatedBy
. Cependant, avec le déclencheur Supprimer, aucune donnée n'est insérée / mise à jour. Existe-t-il un moyen de transmettre des informations au déclencheur de suppression afin qu'il sache qui a supprimé l'enregistrement?
Voici un déclencheur d'insertion / mise à jour
ALTER TRIGGER [dbo].[trg_MyTable_InsertUpdate]
ON [dbo].[MyTable]
FOR INSERT, UPDATE
AS
INSERT INTO AuditTable (IdOfRecordedAffected, UserWhoMadeChanges)
VALUES (inserted.ID, inserted.LastUpdatedBy)
FROM inserted
Utilisation de SQL Server 2012
sql-server
sql-server-2012
trigger
audit
webworm
la source
la source
SUSER_SNAME()
est la clé pour savoir qui a supprimé l'enregistrement.SUSER_SNAME()
cela fonctionnerait dans une situation comme une application Web où un seul utilisateur pourrait être utilisé pour la communication de base de données pour l'ensemble de l'application.Réponses:
Oui: en utilisant une fonction très cool (et sous-utilisée) appelée
CONTEXT_INFO
. Il s'agit essentiellement de mémoire de session qui existe dans toutes les étendues et n'est pas liée par des transactions. Il peut être utilisé pour transmettre des informations (toutes les informations - enfin, toutes celles qui tiennent dans l'espace limité) aux déclencheurs ainsi que des allers-retours entre les appels sous-proc / EXEC. Et je l'ai déjà utilisé pour cette même situation.Les informations de contexte sont VARBINARY (128)
Définir via: SET CONTEXT_INFO
Obtenez via: CONTEXT_INFO ()
Testez avec ce qui suit pour voir comment cela fonctionne. Notez que je me convertis en
CHAR(128)
avant leCONVERT(VARBINARY(128), ..
. Il s'agit de forcer le remplissage pour faciliter la reconversionVARCHAR
lorsque vous le retirezCONTEXT_INFO()
car ilVARBINARY(128)
est rempli à droite avec0x00
s.Résultats:
METTRE TOUS ENSEMBLE:
L'application doit appeler une procédure stockée "Supprimer" qui transmet le nom d'utilisateur (ou autre) qui supprime l'enregistrement. Je suppose que c'est déjà le modèle utilisé car il semble que vous suivez déjà les opérations d'insertion et de mise à jour.
La procédure stockée "Supprimer" permet:
Le déclencheur d'audit:
Veuillez noter que, comme @SeanGallardy l'a souligné dans un commentaire, en raison d'autres procédures et / ou requêtes ad hoc supprimant des enregistrements de ce tableau, il est possible que:
CONTEXT_INFO
n'a pas été défini et est toujoursNULL
:Pour cette raison, j'ai mis à jour ce qui précède
INSERT INTO AuditTable
pour utiliser unCOALESCE
par défaut la valeur. Ou, si vous ne voulez pas de valeur par défaut et avez besoin d'un nom, vous pouvez faire quelque chose de similaire à:CONTEXT_INFO
a été défini sur une valeur qui n'est pas un nom d'utilisateur valide et peut donc dépasser la taille duAuditTable.[UserWhoMadeChanges]
champ:Pour cette raison, j'ai ajouté une
LEFT
fonction pour garantir que tout ce qui est récupéréCONTEXT_INFO
ne cassera pas leINSERT
. Comme indiqué dans le code, il vous suffit de définir la50
à la taille réelle duUserWhoMadeChanges
champ.MISE À JOUR POUR SQL SERVER 2016 ET PLUS RÉCENT
SQL Server 2016 a ajouté une version améliorée de cette mémoire par session: Contexte de session. Le nouveau contexte de session est essentiellement une table de hachage de paires clé-valeur, la "clé" étant de type
sysname
(c'est-à-direNVARCHAR(128)
) et la "valeur" étantSQL_VARIANT
. Sens:CONTEXT_INFO()
(pour plus de détails, veuillez consulter mon article: Pourquoi CONTEXT_INFO () ne renvoie-t-il pas la valeur exacte définie par SET CONTEXT_INFO? )CONTEXT_INFO
)Pour plus de détails, veuillez consulter les pages de documentation suivantes:
la source
@@SPID
. Il s'agit de la mémoire PER-Session / Connection. Une session ne peut pas remplacer les informations de contexte d'une autre session. Et lorsque la session se déconnecte, la valeur disparaît. Il n'y a rien de tel qu'un "élément précédemment défini".Vous ne pouvez pas procéder ainsi, sauf si vous cherchez à enregistrer l'ID utilisateur du serveur SQL plutôt qu'un niveau d'application.
Vous pouvez effectuer une suppression logicielle en ayant une colonne appelée DeletedBy et en la définissant selon vos besoins, puis votre déclencheur de mise à jour peut effectuer la véritable suppression (ou archiver l'enregistrement, j'évite généralement les suppressions matérielles lorsque cela est possible et légal) ainsi que la mise à jour de votre piste d'audit . Pour forcer les suppressions à effectuer de cette façon, définissez un
on delete
déclencheur qui déclenche une erreur. Si vous ne souhaitez pas ajouter une colonne à votre table physique, vous pouvez définir une vue qui ajoute la colonne et définir desinstead of
déclencheurs pour gérer la mise à jour de la table de base, mais cela peut être excessif.la source
SPARSE
colonne SQL Server ?Oui, apparemment il y a deux façons ;-). S'il y a des réserves sur l'utilisation
CONTEXT_INFO
comme je l'ai suggéré dans mon autre réponse ici , j'ai juste pensé à une autre manière qui a une séparation fonctionnelle plus nette des autres codes / processus: utiliser une table temporaire locale.Le nom de la table temporaire doit inclure le nom de la table en cours de suppression car cela l'aidera à être séparé de tout autre code susceptible de s'exécuter dans la même session. Quelque chose dans le sens de:
#<TableName>DeleteAudit
Un avantage pour une table temporaire locale
CONTEXT_INFO
est que si quelqu'un dans un autre processus - qui est en quelque sorte appelé à partir de ce processus "Supprimer" particulier - arrive juste d'utiliser incorrectement le même nom de table temporaire, le sous-processus a) créera un nouveau local table temporaire du nom demandé qui sera distinct de cette table temporaire initiale (même si elle a le même nom), et b) toute instruction DML par rapport à la nouvelle table temporaire locale dans le sous-processus n'affectera aucune donnée de la table temporaire locale créée ici dans le processus parent, donc pas d'écrasement des données. Bien sûr, si un des problèmes de sous - processus une déclaration de DML contre ce nom de table temporaire sans émettre d' abord une CREATE TABLE de ce même nom, ces déclarations DML auront une incidence sur les données de ce tableau. MAIS, à ce stade, nous obtenons vraimentbord-casey ici, encore plus qu'avec la probabilité de chevauchement des utilisations deCONTEXT_INFO
(oui, je sais que c'est arrivé, c'est pourquoi je dis "bord-cas" plutôt que "ça n'arrivera jamais").L'application doit appeler une procédure stockée "Supprimer" qui transmet le nom d'utilisateur (ou autre) qui supprime l'enregistrement. Je suppose que c'est déjà le modèle utilisé car il semble que vous suivez déjà les opérations d'insertion et de mise à jour.
La procédure stockée "Supprimer" permet:
Le déclencheur d'audit:
J'ai testé ce code dans un déclencheur et il fonctionne comme prévu.
la source