我正在尝试利用 SQL Server 2008R MERGE 功能来管理连接表中的父子关系记录。
连接表表示多对多关系,因此它有两个外键对应同一个主键。因此,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]
*/;
在从 Content 表中删除记录之前,是否有任何替代方法可以添加触发器INSTEAD OF INSERT
并且INSTEAD OF UPDATE
不必显式删除 Attachment 表中的任何约束记录?
我可以暂时禁用触发器,但随后我必须明确删除附件表中的约束记录。
我担心添加额外的触发器只是为了适应 MERGE 语句会破坏使用 MERGE 语句的目的。
更新:有没有办法创建一个虚拟 INSTEAD OF INSERT, UPDATE 触发器以使我能够继续使用 MERGE?