SQL Server 2008R MERGE 機能を利用して、結合テーブル内の親子関係レコードを管理しようとしています。
結合テーブルは多対多の関係を表すため、同じ主キーに対して 2 つの外部キーがあります。したがって、ON DELETE CASCADE
使用できません。その代わりに、トリガーを使用しINSTEAD OF DELETE
て結合レコードを削除しているため、制約が削除され、当初意図されていた削除操作を完了することができます。
残念ながら、このシナリオで MERGE を使用しようとすると、次のエラーが発生します。
The target 'Content' of the MERGE statement has an INSTEAD OF trigger on some,
but not all, of the actions specified in the MERGE statement. In a MERGE statement,
if any action has an enabled INSTEAD OF trigger on the target, then all actions
must have enabled INSTEAD OF triggers.
この問題を再現するための T-SQL を次に示します。便宜上、drop ステートメントと select ステートメントをコメントアウトして含めました。
CREATE DATABASE [TestDatabase]
GO
USE [TestDatabase]
GO
CREATE TABLE dbo.[Content] (
ContentID int NOT NULL IDENTITY (1, 1),
Title varchar(255)
)
ALTER TABLE dbo.[Content]
ADD CONSTRAINT PK_Content
PRIMARY KEY CLUSTERED (ContentID)
CREATE TABLE dbo.[Attachment] (
ParentContentID int NOT NULL,
ChildContentID int NOT NULL
)
ALTER TABLE [dbo].[Attachment]
ADD CONSTRAINT [PK_Attachment]
PRIMARY KEY CLUSTERED (
[ParentContentID] ASC,
[ChildContentID] ASC
)
ALTER TABLE dbo.Attachment
ADD CONSTRAINT FK_Attachment_ParentContent
FOREIGN KEY (ParentContentID)
REFERENCES dbo.[Content] (ContentID)
ON UPDATE NO ACTION
ON DELETE NO ACTION
ALTER TABLE dbo.Attachment
ADD CONSTRAINT FK_Attachment_ChildContent
FOREIGN KEY (ChildContentID)
REFERENCES dbo.[Content] (ContentID)
ON UPDATE NO ACTION
ON DELETE NO ACTION
GO
CREATE TRIGGER trContentInsteadOfDelete
ON dbo.[Content]
INSTEAD OF DELETE
AS
SET NOCOUNT ON;
DELETE FROM dbo.[Attachment]
WHERE [ParentContentID] IN (SELECT [ContentID] FROM deleted)
OR [ChildContentID] IN (SELECT [ContentID] FROM deleted)
DELETE FROM dbo.[Content]
WHERE [ContentID] IN (SELECT [ContentID] FROM deleted)
GO
INSERT INTO [Content] ([Title]) VALUES ('a'), ('a'), ('a'), ('b')
GO
INSERT INTO [Attachment] ([ParentContentID], [ChildContentID])
VALUES (1, 2), (1, 4), (3, 4)
GO
MERGE [Content] AS target
USING (VALUES (1, 'a'), (2, 'b'), (NULL, 'b')) AS source ([ContentID], [Title])
ON target.[ContentID] = source.[ContentID]
WHEN MATCHED AND target.[Title] != source.[Title] THEN
UPDATE SET target.[Title] = source.[Title]
WHEN NOT MATCHED BY TARGET THEN
INSERT ([Title]) VALUES (source.[Title])
WHEN NOT MATCHED BY source THEN
DELETE;
/*
USE master
DROP DATABASE [TestDatabase]
SELECT * FROM [Content]
SELECT * FROM [Attachment]
*/;
INSTEAD OF INSERT
Content テーブルからレコードを削除する前に、Attachment テーブル内の制約レコードを明示的に削除せINSTEAD OF UPDATE
ずにトリガーを追加する代替手段はありますか?
トリガーを一時的に無効にすることもできますが、その後、Attachment テーブル内の制約レコードを明示的に削除する必要があります。
MERGE ステートメントに対応するためだけにトリガーを追加すると、MERGE ステートメントを使用する目的が損なわれるのではないかと懸念しています。
更新: ダミーの INSTEAD OF INSERT、UPDATE トリガーを作成して、引き続き MERGE を使用できるようにする方法はありますか?