我可以创建一个虚拟的INSTEAD OF UPDATE,INSERT触发器,这样我就可以使用MERGE和INSTEAD OF DELETE吗?

时间:2012-10-30 21:44:05

标签: sql-server

我尝试利用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 INSERTINSTEAD OF UPDATE添加触发器,而不必显式删除Attachment表中的任何约束记录? < / p> <击>

我可以暂时禁用触发器,但是我必须明确删除附件表中的约束记录。

我担心为了容纳MERGE语句而添加额外的触发器会破坏使用MERGE语句的目的。

更新:有没有办法创建一个虚拟的INSTEAD OF INSERT,UPDATE触发器,使我能够继续使用MERGE?

1 个答案:

答案 0 :(得分:0)

这似乎可以解决问题,但我想知道对性能的影响。

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

CREATE TRIGGER trContentInsteadOfInsertUpdate
    ON dbo.[Content]
    INSTEAD OF INSERT, UPDATE
AS

    SET NOCOUNT ON;

    INSERT INTO dbo.[Content] (
        [Title]
    )
    SELECT
        i.[Title]
    FROM inserted i
    LEFT JOIN dbo.[Content] c ON i.[ContentID] = c.[ContentID]
    WHERE c.[ContentID] IS NULL

    UPDATE c
    SET
        c.[Title] = i.[Title]
    FROM dbo.[Content] c
    JOIN inserted i ON c.[ContentID] = i.[ContentID]
GO