2012-10-30 5 views
0

SQL Server 2008R MERGE 기능을 사용하여 조인 테이블에서 부모 자식 관계 레코드를 관리하려고합니다.대체 대신 INSTEAD OF UPDATE, INSERT 트리거를 만들어서 병합 대신에 DELETE를 사용할 수 있습니까?

조인 테이블은 다 대다 관계를 나타내므로 동일한 기본 키에 대해 두 개의 외래 키가 있습니다. 따라서 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 INSERTINSTEAD OF UPDATE에 트리거를 추가하는 어떤 대안이 있습니까?

일시적으로 트리거를 사용하지 못하게 할 수는 있지만 첨부 파일 테이블의 제약 레코드를 명시 적으로 삭제해야합니다.

MERGE 문을 수용하기위한 추가 트리거를 추가하면 MERGE 문을 사용하는 목적을 무효화하는 것이 우려됩니다.

업데이트 : 병합을 계속 사용하려면 INSERT, UPDATE 트리거의 더미 대신을 만드는 방법이 있습니까?

+1

나는 "당신이 여기에서 무엇을 기대 대답 잘 모르겠어요 : 오류가 명시하고 요구 사항은 [기록]입니다 (http://msdn.microsoft.com/en-us/library/bb510625 (V = SQL .015) .aspx). 아무 것도하지 않는 더미 트리거를 만드는 등의 해결 방법이 가장 좋을 것입니다. – Pondlife

+0

@Pondlife, 저는 병합을 사용하고 분리 된 조인을 정리하는 더 나은 방법을 찾으려합니다. 레코드를 첨부 테이블에. 나는 누군가가 위의 코드에서 설명하는 동일한 결과를 얻을 수있는 더 나은 방법을 희망하고있다. 귀하의 의견을 보내 주셔서 감사합니다. – Kuyenda

답변

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 
관련 문제