SQL Serverでは、トリガーはデータベースオブジェクトであり、データベースまたはサーバーでトリガーイベントが発生するたびに実行されます。トリガーは、達成された条件に基づいて対象となる人々に警告する、仕事を開始する、またはその他の操作などのビジネス要件を達成する上で重要な役割を果たします。 DMLトリガーに関する前回の記事では、トリガー、トリガーの種類、およびDMLトリガーで使用できるさまざまなトリガーオプションについて説明しました。この記事では、SQLDDLおよびLOGONトリガーについて説明します。
DDLトリガー
DDLトリガーは、DDLコマンドとDCLコマンドの両方を含む、さまざまなサーバーまたはデータベーススコープのイベントに対して起動できます。 DDLは、任意のオブジェクトのCREATE、ALTER、DROPに使用されるデータ定義言語を表し、DCLは、GRANT、DENY、REVOKEコマンドなどのデータ制御言語ステートメントを表します。以下は、SQLDDLトリガーの特性です。
- DDLトリガーは、データベースレベルまたはサーバーインスタンスレベルで作成でき、さまざまなDDL操作またはDDLに類似した操作をカバーします。 DCLコマンド。
- DDLトリガーは、FORまたはAFTERトリガータイプとしてのみ呼び出しまたは起動できます。 SQLServerはINSTEADOFDDLトリガーをサポートしておらず、DDLトリガーを介して一部のDDL操作を防止する方法を確認できます。
- SQL Serverには、トリガーイベントに関連する詳細情報を取得するためのDDLトリガー内で使用するEVENTDATA()やIS_MEMBER()などの組み込み関数があります。
- EVENTDATA()関数は、データベースまたはサーバースコープのDDLトリガーまたはログオントリガーのスコープ内で、データベースまたはサーバースコープのイベントに関する完全な詳細をXML形式で返します。 EVENTDATA()関数は、DDLまたはログオンアクティビティを実行するセッションの完全なイベント詳細を返します。 EVENTDATA()は以下の詳細を返します
- EventType –sys.trigger_event_typesテーブルで使用可能なDDLトリガーを起動するイベントのタイプ。
- PostTime –イベントがトリガーまたは投稿された時刻。
- SPID –イベントのセッションID。
- ServerName –イベントがトリガーされたSQLServerインスタンス名。
- LoginName –イベントを実行したSQLServerログイン名。
- UserName –デフォルトでdboになるログインのユーザー名。
- DatabaseName –DDLトリガーが起動されたデータベース名。
- SchemaName –影響を受けたオブジェクトのスキーマ名。
- ObjectName –影響を受けたオブジェクト名。
- ObjectType –テーブル、ビュー、ストアドプロシージャなどのSQLServerオブジェクトのタイプ。
- TSQLCommand –DDLトリガーを呼び出したユーザーによって実行されたT-SQLスクリプト。
- SetOptions –TSQLCommandの実行中にユーザーまたはSSMSなどのクライアントによって使用されるSETオプション。
- CommandText –sys.trigger_event_typesテーブルで指定されたDDLイベントを含む実際のDDLまたはDCLステートメント。
- IS_MEMBER()関数は、現在のユーザーがWindowsグループまたはSQLServerデータベースの役割のメンバーであるかどうかを返します。
- EVENTDATA()関数は、データベースまたはサーバースコープのDDLトリガーまたはログオントリガーのスコープ内で、データベースまたはサーバースコープのイベントに関する完全な詳細をXML形式で返します。 EVENTDATA()関数は、DDLまたはログオンアクティビティを実行するセッションの完全なイベント詳細を返します。 EVENTDATA()は以下の詳細を返します
- システムDMVsys.triggersは、すべてのデータベーススコープトリガーのリストを格納します。以下のクエリを使用して、データベーススコープのすべてのDDLトリガーの詳細を取得できます。
SELECT *
FROM sys.triggers
WHERE type = 'TR';
- システムDMVsys.server_triggersは、すべてのサーバースコープのトリガーのリストを格納します。以下のクエリを使用して、すべてのサーバースコープのDDLトリガーに関する詳細を取得できます。
SELECT *
FROM sys.server_triggers;
- sys.sql_modulesの以下のオプションのいずれかを使用するか、OBJECT_DEFINITION()関数を使用するか、sp_helptextストアドプロシージャを使用してトリガーが暗号化されていない場合、DDLトリガー定義を表示できます。
SELECT OBJECT_SCHEMA_NAME(object_id, db_id()) Schema_name, OBJECT_NAME(object_id) Trigger_Name, definition
FROM sys.sql_modules
WHERE object_id = OBJECT_ID(<trigger_name>);
SELECT OBJECT_DEFINITION (OBJECT_ID(<trigger_name>)) AS ObjectDefinition;
EXEC sp_helptext '<trigger_name>';
- すべての可能なDDLイベントはsys.trigger_event_typesテーブルで利用可能であり、以下のクエリを使用して表示できます。
SELECT *
FROM sys.trigger_event_types;
DDLトリガーの構文は次のとおりです。
CREATE TRIGGER <trigger_name>
ON < ALL SERVER | DATABASE >
[ WITH <DDL_trigger_option> [ ,...n ] ]
{ FOR | AFTER } <event_type>
AS { sql_statement | EXTERNAL NAME <method specifier> }
データベーススコープのDDLトリガーの作成
以下のスクリプトを使用して、すべてのテーブル作成を追跡し、Track_DDL_Changesという名前のログテーブルにログインするデータベーススコープトリガーを作成しましょう。
CREATE TABLE Track_DDL_Changes (EventData xml, PostDtm datetime)
GO
CREATE TRIGGER TR_D_CREATETABLE
ON DATABASE
FOR CREATE_TABLE
AS
BEGIN
INSERT INTO Track_DDL_Changes
SELECT EVENTDATA(),GETDATE()
END
GO
以下のスクリプトを使用して、trigger_testという名前の新しいテーブルを作成し、CREATETABLEイベントが監査されたかどうかを確認しましょう。
CREATE TABLE Trigger_Test ( a int, b datetime);
Track_DDL_Changesテーブルからデータを選択すると、以下に示すように、上記のCREATE_TABLEイベントが正常にキャプチャされたことが示されます。
EventData値をクリックすると、以下に示すように、新しいウィンドウでXML EVENTDATA()値が開きます。
EVENTDATA()関数を介してトリガーイベントに関する完全な詳細を確認できるため、EVENTDATA()関数はすべてのDDLまたはLOGONトリガーに対して重要な役割を果たします。
EVENTDATA()関数とXML解析を使用して、DDLトリガーをさらに強化し、以下のスクリプトを使用してテストデータベースにテーブルを作成できないようにすることができます。
CREATE TRIGGER TR_D_PREVENT_CREATETABLE
ON DATABASE
FOR CREATE_TABLE
AS
BEGIN
SELECT EVENTDATA().value
('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]','nvarchar(max)')
RAISERROR ('Creation of New tables restricted in this database, Kindly contact DBA.', 16, 1)
ROLLBACK
END
GO
データベーススコープトリガーの作成が正常に完了しました。以下のスクリプトを使用して別のテーブルを作成して確認しましょう。
CREATE TABLE Trigger_Test1 (a int, b datetime);
このトリガーにより、このデータベースに新しいテーブルを作成できなくなり、ユーザーにも意味のあるメッセージが残されました。要件に合わせて、他のDDLまたはサーバースコープのイベントも同様に処理できます。
データベーススコープのDDLトリガーを削除するには、次の構文を使用する必要があります。
DROP TRIGGER <trigger_name> ON DATABASE;
そして、今作成したトリガーを削除するには、スクリプトは次のようになります
DROP TRIGGER TR_D_PREVENT_CREATETABLE ON DATABASE;
SSMSでデータベーススコープのDDLトリガーを表示するには、以下に示すように、[テストデータベース]->[プログラマビリティ]->[データベーストリガー]を展開します。
SQL DMLトリガーと同様に、以下に示すように、トリガー名を右クリックするだけで、DDLトリガーを削除、無効化、または有効化できます。
T-SQLを介して、以下の構文を使用して、データベーススコープのDDLトリガーを削除または無効化または有効化できます。
-- DROP Database scoped DDL Trigger
DROP TRIGGER <trigger_name> ON DATABASE;
-- Enable Database scoped DDL Trigger
ENABLE TRIGGER <trigger_name> ON DATABASE;
-- Disable Database scoped DDL Trigger
DISABLE TRIGGER <trigger_name> ON DATABASE;
作成したトリガーを無効にするには、以下のスクリプトを使用する必要がある場合があります。
-- DROP Database scoped DDL Trigger
DROP TRIGGER TR_D_PREVENT_CREATETABLE ON DATABASE;
-- Enable Database scoped DDL Trigger
ENABLE TRIGGER TR_D_PREVENT_CREATETABLE ON DATABASE;
-- Disable Database scoped DDL Trigger
DISABLE TRIGGER TR_D_PREVENT_CREATETABLE ON DATABASE;
サーバースコープのDDLトリガーの作成
サーバースコープのDDLトリガーは、イベントがサーバースコープに基づくことを除いて、データベーススコープのDDLトリガーと同じ構文に従います。
以下のスクリプトを使用して、ユーザーがこのサーバーインスタンスに新しいデータベースを作成できないように、サーバースコープのDDLトリガーを作成してみましょう。
CREATE TRIGGER TR_S_PREVENT_CREATEDATABASE
ON ALL SERVER
FOR CREATE_DATABASE
AS
BEGIN
SELECT EVENTDATA().value
('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]','nvarchar(max)')
RAISERROR ('Creation of New Databases restricted in this Instance, Kindly contact DBA.', 16, 1)
ROLLBACK
END
GO
以下のコマンドを使用して新しいデータベースを作成しようとすると、以下に示すようなエラーが発生します。
CREATE DATABASE DATABASE_TEST;
SSMSでは、以下に示すように、[サーバーオブジェクト]セクションの[トリガー]の下にあるサーバースコープのDDLトリガー。
以下に示すように、サーバースコープのDDLトリガーを右クリックするだけで、サーバースコープのDDLトリガーを削除、無効化、または有効化できます。
T-SQLを介して、以下のコマンドを使用して、ドロップ、無効化、または有効化できます。
-- DROP Server scoped DDL Trigger
DROP TRIGGER TR_S_PREVENT_CREATEDATABASE ON ALL SERVER;
-- Disable Server scoped DDL Trigger
DISABLE TRIGGER TR_S_PREVENT_CREATEDATABASE ON ALL SERVER;
-- Enable Server scoped DDL Trigger
ENABLE TRIGGER TR_S_PREVENT_CREATEDATABASE ON ALL SERVER;
DDLトリガーの目的
- データベースまたはサーバーレベルで発生するDDLイベントを監査するため。
- データベースまたはサーバーレベルでDDLイベントが発生しないようにするため。
- データベースまたはサーバーレベルでDDLイベントが発生したときにアラートを送信します。
ログオントリガー
名前が示すように、ログオントリガーはSQLServerのLOGONイベントに対して実行されます。 Loginイベントの認証フェーズが完了すると、Loginアクティビティに加えてLOGONTriggerスクリプトが実行されます。ログインが正常に認証されない場合、LOGONトリガーは起動されません。ログオントリガーは、サーバーオブジェクトの[トリガー]セクションのSSMSに一覧表示されます。 LOGONトリガーの構文は次のとおりです。
CREATE TRIGGER <schema_name.trigger_name>
ON ALL SERVER
{ FOR| AFTER } LOGON
AS { sql_statement [ ; ] [ ,...n ] | EXTERNAL NAME < method specifier > [ ; ] }
トリガーを作成する
以下に示すように、EVENTDATA()関数からLOGONイベントに関する詳細情報を取得するための単純なLOGONトリガーを作成しましょう。
CREATE TABLE Track_LOGON_EVENTS (EventData xml, PostDtm datetime)
GO
CREATE TRIGGER TR_LOGON
ON ALL SERVER
FOR LOGON
AS
BEGIN
INSERT INTO Track_LOGON_EVENTS
SELECT EVENTDATA(),GETDATE();
END
GO
上記のLOGONトリガーは、DDLトリガーでEVENTDATA()関数を使用しているときに気付いたのと同様のログインアクティビティに関するすべての詳細をキャプチャします。 LOGONトリガーの使用を計画する際は、トリガー内に論理エラーがあるかのように注意する必要があります。これにより、だれもほとんどのユーザーがSQLServerのインスタンスに接続できなくなります。
LOGONトリガーを削除、無効化、または有効化するには、以下のスクリプトを使用できます。
-- DROP LOGON Trigger
DROP TRIGGER TR_LOGON ON ALL SERVER;
-- Disable LOGON Trigger
DISABLE TRIGGER TR_LOGON ON ALL SERVER;
-- Enable LOGON Trigger
ENABLE TRIGGER TR_LOGON ON ALL SERVER;
LOGONトリガーの目的
- サーバーで発生するLOGONイベントを監査するため。
- サーバーでLOGONイベントが発生しないようにするため
- サーバーでLOGONイベントが発生したときにアラートを送信します。
トリガープロパティ
sp_settriggerorder
sp_settriggerorderは、最初と最後のトリガーに対してのみトリガーの実行順序を定義するために使用されます。テーブルに3つ以上のDMLトリガーがある場合(たとえば5つのDMLトリガー)、最初のDMLトリガーと最後のDMLトリガーを定義できますが、中央の3つのトリガーの順序を定義することはできません。
注: FIRSTまたはLASTオプションの設定は、DMLトリガーの特定のイベントカテゴリに固有です。たとえば、3つのINSERTトリガーを持つテーブルでは、どのINSERTトリガーがFIRSTで、どのINSERTトリガーがLASTであるかを定義できます。 INSERT、UPDATE、DELETEのようにテーブルに3つのトリガーがある場合、トリガーの順序条件を設定する必要はありません。
トリガーの順序を設定するための構文は次のようになります。
exec sp_settriggerorder @triggername = '<trigger_schema_name.trigger_name>'
, @order = 'FIRST' | 'LAST'
, @stmttype = '<trigger event type>'
, @namespace = 'DATABASE' | 'SERVER' | 'NULL'
DDLトリガーの場合、最初と最後のサーバースコープトリガーを定義してから、最初と最後のデータベーススコープトリガーを定義できます。たとえば、サーバースコープのトリガーが5つ、データベーススコープのトリガーが5つある場合、順序は次のように定義できます。
- サーバースコープのDDLトリガーの最初のトリガー
- 3つのサーバースコープのDDLトリガーをランダムな順序で
- サーバースコープのDDLトリガーの最後のトリガー。
- データベーススコープのDDLトリガーの最初のトリガー(データベースごとに1つ)
- 3つのデータベーススコープのDDLトリガーをランダムな順序で
- データベーススコープのDDLトリガーの最後のトリガー。
最初または最後のオプションの設定に関しては、データベーススコープのDDLトリガーをデータベース内で順序付けでき、サーバースコープのDDLトリガーをインスタンスレベルで並べ替えることができます。
SQL Serverではテーブル上に多数のトリガーを作成できますが、メンテナンスとトラブルシューティングを改善するために、トリガーの要件を注意深く分析することをお勧めします。
再帰トリガー
SQL Serverは、DMLトリガーの再帰的なトリガーの呼び出しもサポートしています。再帰トリガーは、以下に示すように、直接または間接に分類できます。
直接再帰トリガー –ユーザーまたはアプリケーションがテーブルAのレコードを更新します。テーブルAのUPDATEトリガーAが起動され、テーブルAが再度更新されます。表Aのレコードはトリガーを介して更新されたため、再度UPDATEトリガーAが呼び出され、これが再帰的に発生します。
次のスクリプトを使用して、Salesテーブルに直接再帰トリガーを作成しましょう。
CREATE TRIGGER TR_UPD_Recursive_Sales ON Sales
FOR UPDATE
AS
BEGIN
UPDATE Sales
SET SalesDate = GETDATE()
WHERE SalesId = (SELECT SalesId FROM Inserted)
END
GO
以下のスクリプトを実行します:
UPDATE Sales
SET SalesDate = GETDATE()
WHERE SalesId = 3;
間接再帰トリガー –ユーザーまたはアプリケーションがテーブルAのレコードを更新します。テーブルAのUPDATEトリガーAが起動され、テーブルBのレコードが更新されます。テーブルBにレコードを更新してテーブルAに戻すUPDATEトリガーがある場合、再帰的に発生する表A。
次のスクリプトを使用して、IDR_Test1テーブルとIDR_Test2テーブルに間接再帰トリガーを作成しましょう。
DROP TABLE IDR_Test1
DROP TABLE IDR_Test2
CREATE TABLE IDR_Test1 (PK int NOT NULL);
GO
INSERT INTO IDR_Test1
values (10),(20)
GO
CREATE TABLE IDR_Test2 (PK int NOT NULL);
GO
INSERT INTO IDR_Test2
values (10),(20)
GO
CREATE TRIGGER TR_IDR_Test1
ON IDR_Test1
FOR UPDATE
AS
BEGIN
UPDATE IDR_Test2
SET PK = 30
WHERE PK IN (SELECT PK FROM inserted);
END
GO
CREATE TRIGGER TR_Temp2
ON IDR_Test2
FOR UPDATE
AS
BEGIN
UPDATE IDR_Test1
SET PK = 30
WHERE PK IN (SELECT PK FROM inserted);
END
GO
以下のスクリプトを実行します:
UPDATE IDR_Test1
SET PK = 1
WHERE PK = 10;
データベースレベルでのこれらの種類の再帰的トリガーの呼び出しを回避するために、SQL Serverには、すべてのデータベースレベルでRECURSIVE_TRIGGERSと呼ばれるオプションがあり、再帰的トリガーのトリガーを解除します。デフォルトでは、データベースの再帰トリガーオプションはFalseに設定されています。パフォーマンスへの影響や関連するデータの変更を慎重に検討した後、必要に応じてのみ有効にしてください。
SSMSで、テストデータベースを右クリックし、[プロパティ]を選択します。 ->オプションをクリックします 下にスクロールして、[再帰トリガー]オプションが有効になっているかどうかを確認します。テストデータベースの場合、FalseがRecursive Triggersオプションのデフォルト値であるため、Falseに設定されます。特定のデータベースの[再帰トリガー]オプションをオンにするには、ドロップダウン値をクリックしてTrueに変更し、[OK]をクリックします。
以下に示すように、T-SQLを介して、sys.databases DMVのis_recursive_triggers_on列を確認することにより、テストデータベースの再帰トリガーオプションを確認できます。
select name, is_recursive_triggers_on
from sys.databases
where name = 'test'
データベースの再帰トリガーオプションを変更するには(私の例ではテスト)、以下のスクリプトを実行できます。
ALTER DATABASE [Test] SET RECURSIVE_TRIGGERS ON WITH NO_WAIT
GO
データベースのfalseステータス(デフォルトステータス)に戻すには(私の例ではテスト)、以下のスクリプトを実行します。
ALTER DATABASE [Test] SET RECURSIVE_TRIGGERS OFF WITH NO_WAIT
GO
ネストされたトリガー
再帰的トリガーはネストされたトリガーの典型的な例ですが、複数のトリガーのネストをもたらす他のケースはほとんどありません。 SQL Serverでは、最大32レベルまでのトリガーのネストが許可されており、そのネストレベルを超えるトリガーはSQLServerによってキャンセルされます。 SQL Serverには、ネストされたトリガーオプションを無効にするインスタンス全体の構成があります。 CLRコードまたはマネージコードを使用したSQLServerトリガーのネストは、SQL Serverの範囲外であるため、32レベルの制限に該当しないことに注意してください。デフォルトでは、ネストされたトリガーオプションはすべてのSQL Serverインスタンスで有効になり、必要に応じて無効にできます。
次の手順に従って、ネストされたトリガーオプションがSSMSのインスタンスレベルで有効になっているかどうかを確認できます。
サーバーを右クリックします ->プロパティを選択します ->詳細strong>をクリックします
ネストされたトリガーオプションを無効またはオフにするには、ドロップダウンをクリックしてFalseに変更し、 OKをクリックします。 。
T-SQLを介して、ネストされたトリガーの構成名についてsys.configurations DMVのvalue_in_use列を確認することにより、ネストされたトリガーオプションが有効になっているかどうかを確認できます。
このオプションを無効にするには、以下に示すように、sp_configureシステムストアドプロシージャを使用する必要があります。
EXEC sp_configure 'nested triggers', 0;
GO
RECONFIGURE;
GO
DMLまたはDDLトリガー内で、ネストの現在のレベルを見つけるために、SQL Serverには、トリガーを起動した現在のステートメントに対して実行されたトリガーの数を返すTRIGGER_NESTLEVELという名前の組み込み関数があります。 TRIGGER_NESTLEVEL関数の構文は次のようになります。
SELECT TRIGGER_NESTLEVEL ( object_id, <trigger_type> , <trigger_event_category> )
object_idがトリガーのオブジェクトIDである場合、trigger_typeはAFTERトリガーの場合はAFTER、INSTEAD OFトリガーの場合はIOTになり、trigger_event_categoryはDMLまたはDDLのいずれかになります。
たとえば、ネストレベルのみを10まで許可し、10レベル以降はエラーを発生させる必要がある場合は、次のようにテストトリガーで実行できます。
IF ((SELECT TRIGGER_NESTLEVEL(OBJECT_ID('test_trigger'), 'AFTER’, 'DML’)) > 10)
RAISERROR ('Trigger test_trigger nested more than 10 levels.',16, -1)
暗号化
トリガーロジックまたは定義を暗号化するために、WITH ENCRYPTIONオプションを、他のすべてのSQLServerオブジェクトと同様にトリガー定義で使用できます。
EXECUTEAS句
特定のセキュリティコンテキストを使用してトリガーを実行するには、トリガー定義でEXECUTEAS句を使用できます。
複製不可
レプリケーションの変更によって実行されているときにDMLトリガーが呼び出されないようにするために、サブスクライバデータベース内のすべてのオブジェクトにNOTFORREPLICATIONプロパティが設定されます。
結論
DDLトリガーとログオントリガーの目的、これらのトリガーを作成または削除、無効化、または有効化する方法、およびEVENTDATA()関数を使用する方法を理解した、DDLトリガーとログオントリガーに関する強力な記事を読んでいただきありがとうございます。 DDLまたはログオンアクティビティの追跡。それに加えて、複数のSQL DMLまたはDDLトリガーの実行順序を、再帰トリガーおよびネストトリガーとともに詳細に設定する方法と、再帰トリガーまたはネストトリガーを慎重に処理する方法を学習しました。