誰がレコードを削除したかを知ることができるように、情報を削除トリガーに渡す方法はありますか?
はい:と呼ばれる非常に優れた(そして十分に活用されていない機能)を使用するCONTEXT_INFO
。基本的に、すべてのスコープに存在し、トランザクションに拘束されないセッションメモリです。これは、情報(限られたスペースに収まるすべての情報)をトリガーに渡したり、サブプロシージャ/ EXEC呼び出しの間でやり取りしたりするために使用できます。そして、これとまったく同じ状況で以前に使用しました。
次のようにテストして、動作を確認します。のCHAR(128)
前にに変換していることに注意してくださいCONVERT(VARBINARY(128), ..
。これは、それが簡単に戻って変換するために作るために力の空白パディングにあるVARCHAR
のそれを取得するときCONTEXT_INFO()
以来VARBINARY(128)
で右詰めである0x00
S。
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];
結果:
0x492064656C6574656420414C4C20796F7572207265636F7264732120484120484121202020202020...
I deleted ALL your records! HA HA!
すべてを一緒に入れて:
アプリは、レコードを削除するユーザー名(またはその他)を渡す「削除」ストアドプロシージャを呼び出す必要があります。挿入と更新の操作をすでに追跡しているように見えるので、これはすでに使用されているモデルだと思います。
「削除」ストアード・プロシージャーは次のことを行います。
DECLARE @EncodedUser VARBINARY(128);
SET @EncodedUser = CONVERT(VARBINARY(128),
CONVERT(CHAR(128), @UserName)
);
SET CONTEXT_INFO @EncodedUser;
-- DELETE STUFF HERE
監査トリガーは次のことを行います。
-- 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;
@SeanGallardyがコメントで指摘しているように、他の手順やアドホッククエリがこのテーブルからレコードを削除しているため、次のいずれかになる可能性があることに注意してください:
CONTEXT_INFO
設定されておらず、まだNULL
です:
このため、デフォルト値としてINSERT INTO AuditTable
a COALESCE
を使用するように上記を更新しました。または、デフォルトが不要で名前が必要な場合は、次のようなことを行うことができます。
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
は有効なUserNameではない値に設定されているため、AuditTable.[UserWhoMadeChanges]
フィールドのサイズを超える可能性があります。
このため、LEFT
グラブしたものがをCONTEXT_INFO
壊さないようにする関数を追加しましたINSERT
。コードで述べたように50
、をUserWhoMadeChanges
フィールドの実際のサイズに設定するだけです。
SQL Server 2016以降の更新
SQL Server 2016では、このセッションごとのメモリの改良版であるセッションコンテキストが追加されました。新しいセッションコンテキストは、本質的にはキーと値のペアのハッシュテーブルで、「キー」はタイプsysname
(つまりNVARCHAR(128)
)で、「値」はSQL_VARIANT
です。意味:
- 値の分離があるため、他の用途と競合する可能性が低くなります
- さまざまなタイプを格納でき、値を取得するときに奇妙な動作を心配する必要がなくなります
CONTEXT_INFO()
(詳細については、私の投稿を参照してください:CONTEXT_INFO()がSET CONTEXT_INFOによって設定された正確な値を返さないのはなぜですか?)
- あなたが得る多く(の最大バイト数128に比べて、すべてのキー全体で256キロバイトの合計まで、「バリュー」あたりの最大バイト8000:より多くのスペースを
CONTEXT_INFO
)
詳細については、次のドキュメントページをご覧ください。
SUSER_SNAME()
レコードを削除したユーザーを取得するためのキーです。