Gibt es eine Möglichkeit, Informationen an den Trigger "Löschen" zu übergeben, damit dieser weiß, wer den Datensatz gelöscht hat?
Ja, indem Sie eine sehr coole (und nicht ausreichend genutzte) Funktion verwenden CONTEXT_INFO
. Es ist im Wesentlichen der Sitzungsspeicher, der in allen Bereichen vorhanden ist und nicht an Transaktionen gebunden ist. Es kann verwendet werden, um Informationen (alle Informationen - also alle, die in den begrenzten Raum passen) an Trigger sowie zwischen Sub-Proc / EXEC-Aufrufen hin und her zu übergeben. Und ich habe es schon einmal für genau dieselbe Situation verwendet.
Testen Sie Folgendes, um zu sehen, wie es funktioniert. Beachten Sie, dass ich CHAR(128)
vor dem konvertiere CONVERT(VARBINARY(128), ..
. Dies dient dazu, das Auffüllen von Leerzeichen zu erzwingen, um das Zurückkonvertieren zu erleichtern, VARCHAR
wenn es herausgenommen wird, CONTEXT_INFO()
da VARBINARY(128)
es mit 0x00
s rechts aufgefüllt ist .
SELECT CONTEXT_INFO();
-- Initially = NULL
DECLARE @EncodedUser VARBINARY(128);
SET @EncodedUser = CONVERT(VARBINARY(128),
CONVERT(CHAR(128), 'I deleted ALL your records! HA HA!')
);
SET CONTEXT_INFO @EncodedUser;
SELECT CONTEXT_INFO() AS [RawContextInfo],
RTRIM(CONVERT(VARCHAR(128), CONTEXT_INFO())) AS [DecodedUser];
Ergebnisse:
0x492064656C6574656420414C4C20796F7572207265636F7264732120484120484121202020202020...
I deleted ALL your records! HA HA!
Alles zusammenfügen:
Die App sollte eine gespeicherte Prozedur "Löschen" aufrufen, die den Benutzernamen (oder was auch immer) übergibt, der den Datensatz löscht. Ich gehe davon aus, dass dies bereits das verwendete Modell ist, da es so klingt, als würden Sie bereits Einfüge- und Aktualisierungsvorgänge verfolgen.
Die gespeicherte Prozedur "Löschen" führt Folgendes aus:
DECLARE @EncodedUser VARBINARY(128);
SET @EncodedUser = CONVERT(VARBINARY(128),
CONVERT(CHAR(128), @UserName)
);
SET CONTEXT_INFO @EncodedUser;
-- DELETE STUFF HERE
Der Audit-Trigger führt Folgendes aus:
-- Set the INT value in LEFT (currently 50) to the max size of [UserWhoMadeChanges]
INSERT INTO AuditTable (IdOfRecordedAffected, UserWhoMadeChanges)
SELECT del.ID, COALESCE(
LEFT(RTRIM(CONVERT(VARCHAR(128), CONTEXT_INFO())), 50),
'<unknown>')
FROM DELETED del;
Bitte beachten Sie, dass, wie @SeanGallardy in einem Kommentar hervorhob, aufgrund anderer Verfahren und / oder Ad-hoc-Abfragen beim Löschen von Datensätzen aus dieser Tabelle Folgendes möglich ist:
CONTEXT_INFO
wurde nicht eingestellt und ist noch NULL
:
Aus diesem Grund habe ich das oben Gesagte aktualisiert INSERT INTO AuditTable
, um COALESCE
den Wert als Standardwert zu verwenden. Wenn Sie keine Standardeinstellung wünschen und einen Namen benötigen, können Sie Folgendes tun:
DECLARE @UserName VARCHAR(50); -- set to the size of AuditTable.[UserWhoMadeChanges]
SET @UserName = LEFT(RTRIM(CONVERT(VARCHAR(128), CONTEXT_INFO())), 50);
IF (@UserName IS NULL)
BEGIN
ROLLBACK TRAN; -- cancel the DELETE operation
RAISERROR('Please set UserName via "SET CONTEXT_INFO.." and try again.', 16 ,1);
END;
-- use @UserName in the INSERT...SELECT
CONTEXT_INFO
wurde auf einen Wert festgelegt, der kein gültiger Benutzername ist und daher möglicherweise die Größe des AuditTable.[UserWhoMadeChanges]
Felds überschreitet :
Aus diesem Grund habe ich eine LEFT
Funktion hinzugefügt , um sicherzustellen, dass alles, woraus herausgegriffen CONTEXT_INFO
wird, nicht kaputt geht INSERT
. Wie im Code angegeben, müssen Sie nur 50
die tatsächliche Größe des UserWhoMadeChanges
Felds festlegen .
UPDATE FÜR SQL SERVER 2016 UND NEUER
SQL Server 2016 hat eine verbesserte Version dieses Sitzungsspeichers hinzugefügt: Sitzungskontext. Der neue Sitzungskontext ist im Wesentlichen eine Hash-Tabelle von Schlüssel-Wert-Paaren, wobei der "Schlüssel" vom Typ sysname
(dh NVARCHAR(128)
) und der "Wert" ist SQL_VARIANT
. Bedeutung:
- Es gibt jetzt eine Wertetrennung, die weniger wahrscheinlich mit anderen Verwendungen in Konflikt steht
- Sie können verschiedene Typen speichern, ohne sich um das seltsame Verhalten kümmern zu müssen, wenn Sie den Wert über zurückgeben
CONTEXT_INFO()
(Details finden Sie in meinem Beitrag: Warum gibt CONTEXT_INFO () den von SET CONTEXT_INFO festgelegten genauen Wert nicht zurück? )
- Sie erhalten viel mehr Speicherplatz: maximal 8000 Byte pro "Wert", insgesamt bis zu 256 KB über alle Schlüssel hinweg (im Vergleich zu maximal 128 Byte
CONTEXT_INFO
)
Weitere Informationen finden Sie auf den folgenden Dokumentationsseiten:
SUSER_SNAME()
ist der Schlüssel, um herauszufinden, wer den Datensatz gelöscht hat.