2010-10-29 39 views
2

J'ai une table d'utilisateur, qui a | Prénom | Nom | DateOfBirth | ... et quelques autres colonnes. Sur cette table spécifique, j'ai un déclencheur sur la mise à jour que si quelqu'un change des valeurs d'utilisateur, il crée un audit.Meilleure façon de détecter quelles colonnes ont été mises à jour lors de l'utilisation de triggers

Mon problème est, la gestion veulent est une vérification visuelle displayd int de la manière suivante:

DateChanged |Change      |Details 
-------------------------------------------------------------------------------- 
2010/01/01 |FirstName Changed    |FirstName Changed from "John" to "Joe" 
2010/01/01 |FirstName And Lastname Changed|FirstName Changed from "Smith" to "White "And Lastname changed from "els" to "brown" 
2010/01/01 |User Deleted     |"ark Anrdrews" was deleted 

Je beleive la meilleure façon d'aborder c'est en modifiant la procédure stockée, mais comment puis-je charger le déclencheur pour enregistrer ce genre de choses?

+0

Quel SGBD? Oracle? PostgreSQL? ... –

+0

Basé sur la réponse acceptée, semble être SQL Server. Tag ajouté –

+0

@ GuillermoGutiérrez Lorsque vous ajoutez de telles balises, veuillez indiquer pourquoi dans le champ des commentaires - tout ce que j'ai vu était 'tag' ajouté pour lequel la question ne donnait aucune indication sur un dbm par rapport à un autre. –

Répondre

5

Il existe une fonction que vous pouvez appeler dans un déclencheur appelé COLUMS_UPDATED(). Cela renvoie un bitmap des colonnes dans la table de déclenchement, avec un 1 indiquant que la colonne correspondante dans la table a été modifiée. En soi, ce n'est pas génial, car vous finiriez avec une liste d'index de colonnes, et auriez encore besoin d'écrire une instruction CASE pour déterminer quelles colonnes ont été modifiées. Si vous n'avez pas beaucoup de colonnes qui pourraient ne pas être si mauvaises, mais si vous vouliez quelque chose de plus générique vous pourriez peut-être rejoindre information_schema.columns pour traduire ces index de colonnes en noms de colonnes

Voici un petit exemple pour montrer le tri de chose que vous pourriez faire:

CREATE TABLE test (
ID Int NOT null IDENTITY(1,1), 
NAME VARCHAR(50), 
Age INT 
) 

GO 
--------------------------------------- 
CREATE TRIGGER tr_test ON test FOR UPDATE 

AS 

DECLARE @cols varbinary= COLUMNS_UPDATED() 
DECLARE @altered TABLE(colid int) 
DECLARE @index int=1 

WHILE @cols>0 BEGIN 
    IF @cols & 1 <> 0 INSERT @altered(colid) VALUES(@index) 
    SET @[email protected]+1 
    SET @[email protected]/2 
END 

DECLARE @text varchar(MAX)='' 
SELECT @[email protected]+C.COLUMN_NAME+', ' 
FROM information_schema.COLUMNS C JOIN @altered A ON c.ordinal_position=A.colid 
WHERE table_name='test' 

PRINT @text 

GO 
------------------------------------------------------ 
INSERT test(NAME, age) VALUES('test',12) 
UPDATE test SET age=15 
UPDATE test SET NAME='fred' 
UPDATE test SET age=18,NAME='bert' 
DROP TABLE test 
+0

merci, apprécié –

1

MS SQL Server a une fonction UPDATED(). Il vous permet de spécifier un nom de champ pour indiquer si des enregistrements ont subi ce changement de champ.

Mon expérience, cependant, est que la fonctionnalité souhaitée dépasse souvent les limites d'une telle fonction générique. Normalement, je finis simplement par joindre la pseudo-table INSERTED à la pseudo-table DELETED et les comparer moi-même.

* Une telle comparaison supposait que la table avait un identificateur unique, qu'il s'agisse d'un seul champ ou d'une clé composée d'une certaine manière.