2009-04-13 8 views
1

Ce que j'essaie de faire est de trouver quels champs ont été mis à jour et enregistrer la modification dans une table différente.Historique basé sur le déclencheur

DECLARE 
    @BillNo int, 
    @column_name varchar(500) 

SELECT @BillNo = BillNo FROM INSERTED 
DECLARE HistoryMonitorLoop CURSOR FOR 
    SELECT  
     column_name 
    FROM 
     information_schema.columns 
    WHERE 
     table_name = 'Shipment'; 
OPEN HistoryMonitorLoop 
FETCH next FROM HistoryMonitorLoop INTO @column_name 
WHILE @@Fetch_status = 0 
BEGIN 
    DECLARE 
     @OldValue varchar(500), 
     @NewValue varchar(500) 
    SET @OldValue = (SELECT @column_name FROM Deleted); 
    SET @NewValue = (SELECT @column_name FROM Inserted); 
    IF(@OldValue != @NewValue) 
    BEGIN 
     DECLARE @Comment varchar(5000) 
     SELECT @Comment = @column_name + ' Changed from ' + @OldValue + ' to ' + @NewValue 
     EXEC ShipmentNote_Insert @[email protected],@CoordinatorID=1,@[email protected] 
    END 
    FETCH next FROM HistoryMonitorLoop INTO @column_name 
END 
CLOSE HistoryMonitorLoop 
DEALLOCATE HistoryMonitorLoop 

ce qui se passe est le

SET @OldValue = (SELECT @column_name FROM Deleted); 
SET @NewValue = (SELECT @column_name FROM Inserted); 

sont le réglage de la @OldValue et @NewValue = au columnname au lieu de la valeur de la colonne - sql est en train de traiter comme SET @OldValue = (SELECT 'column_name' FROM Deleted);

+0

Alors, le script fonctionne-t-il? Avez-vous des erreurs? Est-ce que vous demandez simplement si cela vous semble correct avant de le tester? – BradC

+0

et ?, Quelle est la question? –

+0

ce qui se passe est SET @OldValue = (SELECT @column_name FROM Deleted); SET @NewValue = (SELECT @column_name FROM inséré); définissent @OldValue et @NewValue = sur le nom de la colonne au lieu de la valeur de la colonne –

Répondre

1

Voir cette Pop on the Audit Trail Il utilise une requête dans une boucle par opposition à un curseur, pour faire exactement ce que vous voulez faire.

+0

qui l'a fait, maintenant tout ce que je dois faire est de comprendre comment;) –

0

Cette coutume travail :

SET @OldValue = (SELECT @column_name FROM Deleted); 
SET @NewValue = (SELECT @column_name FROM Inserted); 

Vous essayez ici de créer un SQL dynamique, ce qui ne fonctionnera pas. Vous devez coder en dur le SQL, la variable @column_name ne sera pas remplacée dynamiquement par sa valeur, car le SQL du déclencheur est analysé une fois, avant que le déclencheur s'exécute. Avec cela, vous obtiendrez probablement (en fonction de vos paramètres) la valeur littérale du nom de la colonne.

Il est possible d'obtenir SQL dynamique (en se connectant au serveur dans un autre processus, ou MySQl en créant une déclaration préparée), mais il est impossible de le faire et référence la « magie » INSERTED et DELETED pseudo-tables disponibles dans un déclencheur. Par conséquent, votre utilisation intelligente de information_schema.columns ne fonctionnera pas. Ce que vous pouvez faire est de tirer parti de cette habileté pour écrire une procédure stockée pour générer le déclencheur (c'est en fait ce que j'ai fait quand j'ai dû écrire des déclencheurs d'audit). Ensuite, chaque fois que vous modifiez la table Shipment, vous devrez exécuter le sp pour générer le "create trigger ...." statmentnt, puis exécutez cette instruction générée pour recréer le déclencheur.

+0

ShipmentNote_Insert ajoute dans un horodatage de sorte que ce n'est pas un problème. Dans la mesure où la performance a frappé les données dans la table des expéditions elle-même ne sont pas mises à jour souvent, mais quand il le faut, nous devons savoir ce qui a été changé, une application tierce utilise les avis. la structure de la table est très fluide maintenant –

+0

Ok, alors, quelle est votre question? – tpdi

3

Ce que je suis en train de faire est de savoir quels champs ont été mis à jour

Dans SQL Server, il y a deux fonctions qui fait exactement ce que vous recherchez.

  • Columns_Updated() - Vérifier si un ou plusieurs colonne (s) est/sont insérés/supprimés dans les trigger
  • Update() - Vérifier si une colonne unique est mis à jour dans la gâchette
0

Je repenserais l'ensemble de votre processus. Les déclencheurs peuvent être d'énormes destructeurs de performance lorsqu'ils sont mal écrits. Chaque fois que vous pensez que vous devez utiliser un curseur ou une boucle, détrompez-vous. Vous devez le faire en mode basé sur un ensemble.

Nous utilisons une approche à deux tables. Un qui enregistre les détails sur quand et qui a changé la table et une table connexe qui contient l'information qui a été changée. Cela nous permet de voir tous les enregistrements qui ont été modifiés en même temps.Nous utilisons une déclaration mise à jour pour chaque champ pour remplir la deuxième table quelque chose comme:

if (update([test])) 
    begin 
    insert [myAudit].dbo.[mytableAuditLogDetail](AuditLogID, ID, ColumnName, 
               OldValue, NewValue) 
    select 
     @AuditLogID, 
     i.[mytableid]), 
     'test', 
     convert(varchar(8000), d.[test], 0), 
     convert(varchar(8000), i.[test], 0) 
    from inserted i 
    inner join deleted d on i.[mytableid]=d.[mytableid] 
     and (
     (i.[test] <> d.[test]) or 
     (i.[test] is null and d.[test] Is Not Null) or 
     (i.[test] is not null and d.[test] Is Null) 
     )   
    end 

nous reconstruisons le code de déclenchement dynamiquement à chaque fois que le schéma est changé, mais le déclencheur lui-même est pas dynamique. Notre processus de déclenchement fonctionne très rapidement même lorsque nous effectuons de grandes importations.