DML トリガー ステートメントでは、削除されたテーブルと挿入されたテーブルの 2 つの特殊なテーブルが使用されます。 SQL Server では、これらのテーブルが自動的に作成および管理されます。 これらの一時メモリ常駐テーブルを使用して、特定のデータ変更の影響をテストしたり、DML トリガー アクションの条件を設定したりできます。 テーブル内のデータを直接変更したり、テーブルに対してデータ定義言語 (DDL) 操作 (CREATE INDEX など) を実行したりすることはできません。
DML トリガーでは、挿入されたテーブルと削除されたテーブルは、主に次の処理を実行するために使用されます。
テーブル間の参照整合性を拡張します。
ビューの基になるベース テーブルにデータを挿入または更新します。
エラーをテストし、エラーに基づいてアクションを実行します。
データ変更の前後のテーブルの状態の違いを見つけ、その違いに基づいてアクションを実行します。
削除されたテーブルには、DELETE および UPDATE ステートメント中に影響を受ける行のコピーが格納されます。 DELETE ステートメントまたは UPDATE ステートメントの実行中に、トリガー テーブルから行が削除され、削除されたテーブルに転送されます。 通常、削除されたテーブルとトリガー テーブルには共通の行がありません。
挿入されたテーブルには、INSERT および UPDATE ステートメント中に影響を受ける行のコピーが格納されます。 挿入または更新トランザクション中に、挿入されたテーブルとトリガー テーブルの両方に新しい行が追加されます。 挿入されたテーブル内の行は、トリガー テーブル内の新しい行のコピーです。
更新トランザクションは、削除操作とそれに続く挿入操作に似ています。古い行が最初に削除されたテーブルにコピーされ、次に新しい行がトリガー テーブルと挿入されたテーブルにコピーされます。
トリガー条件を設定する場合は、トリガーを発生したアクションに対して、挿入されたテーブルと削除されたテーブルを適切に使用します。 DELETE のテスト時に INSERT または挿入されたテーブルをテストするときに削除されたテーブルを参照してもエラーは発生しませんが、このような場合、これらのトリガー テスト テーブルには行は含まれません。
注
トリガー アクションがデータ変更効果の行数に依存する場合は、複数行のデータ変更 (SELECT ステートメントに基づく INSERT、DELETE、または UPDATE) のテスト (@@ROWCOUNTの検査など) を使用し、適切なアクションを実行します。
SQL Server 2014 では、AFTER トリガーの挿入および削除されたテーブルの text、 ntext、または image 列参照を使用できません。 ただし、これらのデータ型は下位互換性のみを目的として含まれています。 大きなデータに適したストレージは、 varchar(max)、 nvarchar(max)、および varbinary(max) のデータ型を使用することです。 AFTER トリガーと INSTEAD OF トリガーの両方で、挿入されたテーブルと削除されたテーブルのデータの varchar(max)、 nvarchar(max)、および varbinary(max) がサポートされます。 詳細については、「 CREATE TRIGGER (Transact-SQL)」をご覧ください。
トリガーに挿入されたテーブルを使用してビジネス ルールを適用する例
CHECK 制約は、列レベルまたはテーブル レベルの制約が定義されている列のみを参照できるため、テーブル間制約 (この場合はビジネス ルール) をトリガーとして定義する必要があります。
次の例では、DML トリガーを作成します。 このトリガーは、新しい発注書を PurchaseOrderHeader テーブルに挿入しようとしたときに、仕入先の信用格付けが適切であることを確認します。 挿入した発注書に対応する仕入先の信用格付けを取得するには、 Vendor テーブルを参照し、挿入されたテーブルと結合する必要があります。 信用格付が低すぎると、メッセージが表示され、挿入は実行されません。 この例では、複数行データの変更は許可されないことに注意してください。 詳細については、「 複数行のデータを処理する DML トリガーの作成」を参照してください。
USE AdventureWorks2012;
GO
IF OBJECT_ID ('Purchasing.LowCredit','TR') IS NOT NULL
DROP TRIGGER Purchasing.LowCredit;
GO
-- This trigger prevents a row from being inserted in the Purchasing.PurchaseOrderHeader table
-- when the credit rating of the specified vendor is set to 5 (below average).
CREATE TRIGGER Purchasing.LowCredit ON Purchasing.PurchaseOrderHeader
AFTER INSERT
AS
IF EXISTS (SELECT *
FROM Purchasing.PurchaseOrderHeader p
JOIN inserted AS i
ON p.PurchaseOrderID = i.PurchaseOrderID
JOIN Purchasing.Vendor AS v
ON v.BusinessEntityID = p.VendorID
WHERE v.CreditRating = 5
)
BEGIN
RAISERROR ('A vendor''s credit rating is too low to accept new
purchase orders.', 16, 1);
ROLLBACK TRANSACTION;
RETURN
END;
GO
-- This statement attempts to insert a row into the PurchaseOrderHeader table
-- for a vendor that has a below average credit rating.
-- The AFTER INSERT trigger is fired and the INSERT transaction is rolled back.
INSERT INTO Purchasing.PurchaseOrderHeader (RevisionNumber, Status, EmployeeID,
VendorID, ShipMethodID, OrderDate, ShipDate, SubTotal, TaxAmt, Freight)
VALUES (
2
,3
,261
,1652
,4
,GETDATE()
,GETDATE()
,44594.55
,3567.564
,1114.8638 );
GO
INSTEAD OF トリガーでの挿入および削除されたテーブルの使用
テーブルで定義されている INSTEAD OF トリガーに渡される挿入テーブルと削除テーブルは、AFTER トリガーに渡される挿入テーブルと削除テーブルと同じ規則に従います。 挿入されたテーブルと削除されたテーブルの形式は、INSTEAD OF トリガーが定義されているテーブルの形式と同じです。 挿入されたテーブルと削除されたテーブルの各列は、ベース テーブルの列に直接マップされます。
INSTEAD OF トリガーを使用してテーブルを参照する INSERT ステートメントまたは UPDATE ステートメントで列の値を指定する必要がある場合に関する次の規則は、テーブルに INSTEAD OF トリガーがない場合と同じです。
timestampデータ型の計算列または列には値を指定できません。そのテーブルに対して IDENTITY_INSERT が ON でない限り、IDENTITY プロパティを持つ列には値を指定できません。 IDENTITY_INSERTが ON の場合、INSERT ステートメントは値を指定する必要があります。
INSERT ステートメントは、DEFAULT 制約を持たないすべての NOT NULL 列に値を指定する必要があります。
計算列、ID 列、または
timestamp列を除くすべての列の場合、NULL を許容する列、または DEFAULT 定義を持つ NOT NULL 列の値は省略可能です。
INSERT、UPDATE、または DELETE ステートメントが INSTEAD OF トリガーを持つビューを参照すると、データベース エンジンはテーブルに対して直接アクションを実行する代わりにトリガーを呼び出します。 トリガーは、挿入および削除されたテーブルに表示される情報を使用して、ビュー用に作成された挿入および削除されたテーブルの情報の形式がベース テーブルのデータの形式と異なる場合でも、要求されたアクションをベース テーブルに実装するために必要なステートメントを作成する必要があります。
ビューで定義されている INSTEAD OF トリガーに渡される挿入テーブルと削除されたテーブルの形式は、ビューに対して定義されている SELECT ステートメントの選択リストと一致します。 例えば次が挙げられます。
USE AdventureWorks2012;
GO
CREATE VIEW dbo.EmployeeNames (BusinessEntityID, LName, FName)
AS
SELECT e.BusinessEntityID, p.LastName, p.FirstName
FROM HumanResources.Employee AS e
JOIN Person.Person AS p
ON e.BusinessEntityID = p.BusinessEntityID;
このビューの結果セットには、 int 列と 2 つの nvarchar 列の 3 つの列があります。 ビューで定義されている INSTEAD OF トリガーに渡される挿入および削除されたテーブルには、BusinessEntityIDという名前のint列、LNameという名前のnvarchar列、および FName という名前のnvarchar列もあります。
ビューの選択リストには、1 つのベース テーブル列に直接マップされない式を含めることもできます。 定数や関数の呼び出しなど、一部のビュー式は列を参照せず、無視できます。 複合式は複数の列を参照できますが、挿入されたテーブルと削除されたテーブルの値は、挿入された行ごとに 1 つだけです。 複雑な式を持つ計算列を参照する場合、ビュー内の単純な式にも同じ問題が適用されます。 ビューの INSTEAD OF トリガーは、これらの種類の式を処理する必要があります。