2009-04-13 4 views
1

Was ich versuche zu tun ist herauszufinden, welche Felder aktualisiert wurden und die Änderung in einer anderen Tabelle aufzeichnen.Auslöser basierte Geschichte

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 

was die

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

setzen die @OldValue und @NewValue = auf den Spalten anstelle des Wertes der Spalte geschieht - SQL verarbeitet es als SET @OldValue = (SELECT 'column_name' FROM Deleted);

+0

Also, funktioniert das Skript? Erhalten Sie Fehler? Fragst du nur, ob es in Ordnung ist, bevor du es testest? – BradC

+0

und ?, was ist die Frage? –

+0

was passiert ist SET @OldValue = (SELECT @column_name VON Gelöscht); SET @NewValue = (SELECT @column_name FROM eingefügt); setzen @OldValue und @NewValue = auf den Spaltennamen anstatt auf den Wert der Spalte –

Antwort

1

dieses Pop on the Audit Trail Siehe Es verwendet eine Abfrage in einer Schleife im Gegensatz zu einem Cursor, um genau das zu tun, was Sie tun möchten.

+0

das hat es getan, jetzt muss ich nur noch herausfinden, wie;) –

0

Dies wird nicht funktionieren :

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

Du versuchst dynamische SQL hier, die nicht funktionieren wird. Sie müssen das SQL fest codieren, die Variable @column_name wird nicht dynamisch durch ihren Wert ersetzt, da die SQL des Triggers einmal geparst wird, bevor der Trigger ausgeführt wird. Damit erhalten Sie (abhängig von Ihren Einstellungen) wahrscheinlich den Literalwert des Spaltennamens.

Es ist möglich, dynamischen SQL zu erhalten (durch in einem anderen Prozess auf den Server zu verbinden, oder in MySQl durch eine vorbereitete Erklärung zu schaffen), aber es ist nicht möglich, dass und Referenz der „Magie“ INSERTED zu tun und DELETED Pseudo-Tabellen in einem Trigger verfügbar.

So Ihre clevere Verwendung von information_schema.columns wird nicht funktionieren. Was Sie tun können, ist diese Cleverness zu nutzen, um eine gespeicherte Prozedur zu schreiben, um den Trigger zu generieren (das ist genau das, was ich tat, als ich Auditing-Trigger schreiben musste). Wenn Sie dann die Tabelle Shipment ändern, müssen Sie den Befehl sp ausführen, um den Befehl "create trigger ...." statmentnt zu generieren, und dann die generierte Anweisung ausführen, um den Trigger neu zu erstellen.

+0

Der ShipmentNote_Insert fügt einen Datumsstempel hinzu, so dass dies kein Problem darstellt. Was die Leistung betrifft, werden die Daten in der Versandtabelle selbst nicht oft aktualisiert, aber wenn wir wissen müssen, was geändert wurde, verwendet eine Drittanbieter-App die Benachrichtigungen. Die Struktur des Tisches ist momentan sehr flüssig –

+0

Ok, was ist dann deine Frage? – tpdi

3

Was ich versuche, ist herauszufinden, welche Felder

aktualisiert wurden

In SQL Server gibt es zwei Funktionen, die genau das tut, was Sie suchen.

  • Columns_Updated() - Überprüfen Sie, ob eine oder mehrere Spalte (n) wird/eingefügt/
  • Update() innerhalb Trigger gelöscht - Überprüfen Sie, ob eine einzelne Spalte
innerhalb Trigger aktualisiert
0

Ich würde Ihren gesamten Prozess überdenken. Trigger können große Leistungs-Killer sein, wenn sie falsch geschrieben werden. Immer wenn Sie denken, dass Sie einen Cursor oder eine Schleife verwenden müssen, denken Sie noch einmal nach. Sie müssen dies auf einer Set-basierten Weise tun.

Wir verwenden einen Zwei-Tabellen-Trigger-Ansatz. Eine, die die Details darüber speichert, wann und wer die Tabelle geändert hat und eine verwandte Tabelle, die die geänderten Informationen enthält. Dies hilft uns, alle Datensätze zu sehen, die auf einmal geändert wurden.Wir verwenden eine aktualisierte Erklärung für jedes Feld wie die zweite Tabelle, etwas zu füllen:

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 

Wir bauen den Trigger-Code dynamisch jedes Mal das Schema geändert wird, aber der Auslöser selbst ist nicht dynamisch. Unser Trigger-Prozess läuft sehr schnell, selbst wenn wir große Importe durchführen.