背景情報:
SYSTEM_USER
の結果は、トリガーで呼び出されたときに常に同じになると思います。UserId
が与えられます(ストアドプロシージャでのみ実行されます)。私が遭遇した問題は、ユーザーがレコードを削除するときに、誰がそれをしたのか知りたいということです。同じログインによって行われるため、すべてのアクションがサービスによって行われたのではなく、どのユーザーがそれを実行したのかを確認したいと思います。更新時にModifiedBy
で送信されるを介して更新されるUserId
列があるため、これは更新に関する問題ではありません。
問題は:SYSTEM_USER
を設定する方法、または削除が実行されたときにユーザー情報をトリガーに取り込む方法はありますか?
私が現在持っている「最良の」アイデアは、それが良いアイデアかどうかはまだわかりませんが、サービスで、現在のUserId
がユーザーとしてデータベースにあるかどうかを確認することです。そうでない場合は、それらのユーザーオブジェクトを作成します。次に、EXECUTE AS User = @UserId
を使用してストアドプロシージャを実行します。次に、ストアドプロシージャでDMLが実行され、トリガーが起動すると、SYSTEM_USER
はEXECUTE AS
からユーザーを返す必要があります。
(他の問題によっては)EXECUTE AS User = @UserId
を使用するのが最善の方法かもしれませんが、次の代替アプローチがあります。
ストアドプロシージャ内、またはSQLセッションでDELETE
を実行する前の次のコマンドを実行します。
SET CONTEXT_INFO @UserId
次に、トリガーでこの値を取得できます
SELECT @var = CAST(CAST(CONTEXT_INFO() As Varbinary(4)) As Int)
これにはいくつかの欠点がありますが、最も重要なことは、一度に複数のものに対してCONTEXT_INFOを簡単に使用できないことです。
ユーザーコンテキストを個々のログインからサービスログインに変更する方法によっては、ORIGINAL_LOGIN()が役立つ場合があります。
http://technet.Microsoft.com/en-us/library/ms189492.aspx
「この関数は、元の接続コンテキストのIDの監査に役立ちます。SESSION_USERやCURRENT_USERなどの関数は現在実行中のコンテキストを返しますが、ORIGINAL_LOGINは、そのセッションでSQL Serverのインスタンスに最初に接続したログインのIDを返します。」
テーブルにHost_Name
を追加してみることもできます。ログインを共有している状況では、95%の人が自分のマシンで作業しているため、通常はマシン名で個人を追跡できます。常に機能するとは限りませんが、有用な副次的な情報になる場合があります。
SELECT Host_name FROM sys.dm_exec_sessions WHERE session_id = @@SPID
残念ながら、ホストが常にWebアプリケーション自体になるWebアプリケーションを使用している場合、これは機能しませんが、試してみる価値はあります。