SQL Server 2008 R2に取り組んでいます。
tiu_benefitという名前のAFTER INSERT、UPDATEトリガーがあるテーブルbenefitがあります。
このテーブルのUPDATEステートメントを記述して1行を更新したいのですが、そのトリガーを起動したくありません。更新前にトリガーを無効にしてから、更新後にトリガーを有効にできることを知っています。
DISABLE TRIGGER tiu_benefit ON benefit;
GO
UPDATE benefit SET editor = 'srh' where benefit_id = 9876
GO
ENABLE TRIGGER tiu_benefit ON benefit;
GO
ただし、この無効化と有効化のトリガーは、現在ログインしているすべてのユーザーに影響します。したがって、スクリプトがトリガーを無効にしている間に別のユーザーがUPDATE/INSERTを実行する可能性があります。そのため、現在のセッションでトリガーの無効化と有効化のみを行います。出来ますか?はいの場合、方法を教えてください。
ありがとう
私はこれについていくつかのテストを行いましたが、単一のトランザクションでプロセスを実行する場合は問題ないと思います。
BEGIN TRANSACTION
GO
DISABLE TRIGGER tiu_benefit ON benefit;
GO
UPDATE benefit
SET editor = 'srh'
WHERE benefit_id = 9876
GO
ENABLE TRIGGER tiu_benefit ON benefit;
GO
--Decide to commit or rollback
--commit
--rollback
テストでは、最初にBEGIN TRANSACTION
とDISABLE TRIGGER
のみを強調表示して実行しました。次に、新しい(2番目の)クエリウィンドウを開いて、ベーステーブルに対してさまざまなDMLステートメント(SELECT
、INSERT
、UPDATE
DELETE
)を実行しようとしました。 2番目のクエリウィンドウでベーステーブルにアクセスするすべての試行は、明示的なトランザクションを使用してウィンドウが保持するロックを待機しました。明示的なトランザクションをコミット(またはロールバック)すると、2番目のウィンドウがテーブルにアクセスできるようになりました。
あなたの問題を解決するために、私たちは問題に対してプログラム的なアプローチを取る必要があります。ここには2つのルートがあります。これらのアプローチが必要な理由は、特定のステートメントのトリガーを無効にすることはできず、テーブル全体に対してのみ無効にすることができるためです。
オプション1:Context_Info()
MS SQLのヒントのサミュエルヴァンガ の良い例がありました:
USE AdventureWorks;
GO
-- creating the table in AdventureWorks database
IF OBJECT_ID('dbo.Table1') IS NOT NULL
DROP TABLE dbo.Table1
GO
CREATE TABLE dbo.Table1(ID INT)
GO
-- Creating a trigger
CREATE TRIGGER TR_Test ON dbo.Table1 FOR INSERT,UPDATE,DELETE
AS
DECLARE @Cinfo VARBINARY(128)
SELECT @Cinfo = Context_Info()
IF @Cinfo = 0x55555
RETURN
PRINT 'Trigger Executed'
-- Actual code goes here
-- For simplicity, I did not include any code
GO
これで、サミュエルはトリガーを実行したくない場合、これを使用します。
SET Context_Info 0x55555
INSERT dbo.Table1 VALUES(100)
Context_Info
は、次のシステムビューを使用して、現在のセッションに関する情報を取得します。
sys.dm_exec_requests
sys.dm_exec_sessions
sys.sysprocesses
ここでの考え方は、設定しているバイナリ文字列が現在のセッションにのみ公開されるため、トリガーがセッション中に実行されると、Context_info
関数のスコープと変数設定が表示され、代わりにトリガーの一部をエスケープします。
オプション2:一時テーブル
Itzik Ben-Gan は、彼の著書 "Inside Microsoft SQL Server 2008 T-SQL Programming:T-SQL Programming"に 偉大な解決策 が含まれています。 T-SQLクエリ 。 context_info
関数に対するこれの主な問題は、TempDBの小さなオーバーヘッドです。
驚きを台無しにして、本の陰謀を台無しにしないようにするには(購入して読む価値があると感じました)、トリガーを変更します。
トリガーは一時テーブルのチェックを実行する必要があります。一時テーブルが存在する場合、トリガーは終了してアクションを実行しないことを認識している必要があります。
実行するupdateステートメントで、最初に一時テーブルを作成します。トリガーと同じトランザクションで表示され、トリガーがステートメントを無視する原因になります。
トリガーの例:
CREATE TRIGGER TRIGGERNAME ON TABLENAME for INSERT AS
IF OBJECT_ID('tempdb..#FAKETEMPTABLE') IS NOT NULL RETURN;
GO
トリガーを実行させたくないときにステートメントを開始する例:
CREATE TABLE #FAKETEMPTABLE(col1 SMALLINT);
あなたの例のためにそれをまとめると:
ALTER TRIGGER tiu_benefit ON benefit FOR
...
AS
...
IF OBJECT_ID('tempdb..#FAKETEMPTABLE') IS NOT NULL RETURN;
--... rest of code here
GO
CREATE TABLE #FAKETEMPTABLE(col1 SMALLINT);
UPDATE benefit SET editor = 'srh' where benefit_id = 9876;
GO
_CONTEXT_INFO
_または新しい_SESSION_CONTEXT
_を使用します。どちらもセッションベースの値です。
_CONTEXT_INFO
_は、単一のVARBINARY(128)
値です。これは、少なくともSQL Server 2000以降で使用できます。_CONTEXT_INFO
_は、_VIEW SERVER STATE
_ DMVによって返されるフィールドであるため、_sys.dm_exec_sessions
_を持つすべてのユーザーが表示できます。私は以前にこれを使用したことがあり、それは非常にうまく機能します。
SET CONTEXT_INFO で設定
経由で取得 CONTEXT_INFO() または sys.dm_exec_sessions
_CONTEXT_INFO
_に格納する値のタイプによっては、注意が必要ないくつかのニュアンスがあります。それについては、次のブログ記事で説明します。
Session_contextは、_SQL_VARIANT
_値のキーと値のペアです。これはSQL Server 2016で導入されました。さまざまな目的での値の分離は非常に便利です。 Session_contextは、現在のセッションでのみ表示できます。
sp_set_session_context でこの値を設定します
SESSION_CONTEXT でこの値を取得します
ローカル一時テーブルオプション、さらにはトリガーの無効化/有効化オプションについて考慮すべき1つのこと:どちらも、ある程度のロックとトランザクションログアクティビティを必要とします。これらのオプションは両方とも、たとえ最小限であっても、競合の可能性を高めます。 2つの「コンテキスト」オプションは、軽量/メモリのみである必要があります。