ON DELETE CASCADE与MS SQL Server中的同一个表的多对多关系

时间:2017-10-18 18:25:22

标签: sql sql-server

注意:此问题似乎是在Cascade delete on many-to-many between same table之前提出的,但没有得到满意的答复。

我有一张桌子,友谊(MemberId,FriendId),允许会员将另一位会员添加为朋友。

CREATE TABLE dbo.FRIENDSHIP(
         MemberId         INT NOT NULL
       , FriendId         INT NOT NULL
       , DateCreated      DATE NOT NULL DEFAULT CURRENT_TIMESTAMP
  CONSTRAINT pk_friendship PRIMARY KEY( MemberId, FriendId ),
  CONSTRAINT fk_friendship_member FOREIGN KEY( MemberId ) REFERENCES Member( MemberId ) ON DELETE CASCADE,
  CONSTRAINT fk_friendship_friend FOREIGN KEY( FriendId ) REFERENCES Member( MemberId ) ON DELETE CASCADE
);

当我运行此脚本时,我看到以下错误:

  

在表格上引入FOREIGN KEY约束'fk_friendship_friend'   'FRIENDSHIP'可能导致循环或多个级联路径。指定ON   DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他FOREIGN KEY   约束

显然,每当 成员被删除时,我都希望删除友谊中的记录;我也不希望任何一个字段都可以为空。

经过一番研究,我看到有人建议使用触发器。所以我创建了一个:

CREATE OR ALTER TRIGGER friendship_cascade_delete
    ON Member
   FOR DELETE
    AS
DELETE FROM Friendship
 WHERE MemberId IN( SELECT MemberId
                      FROM deleted )
    OR FriendId IN( SELECT MemberId
                     FROM deleted );

但是当我去删除会员时,我仍然会收到错误:

  

DELETE语句与REFERENCE约束冲突   “fk_friendship_member”。冲突发生在数据库“CVGS”中,   表“dbo.FRIENDSHIP”,列'MemberId'。

所以它甚至没有达到触发触发器的程度。如果我删除fk_friendship_member和fk_friendship_friend,则触发器正常工作 - 但我不确定是否要删除这些约束。

有没有办法获得我想要的行为,而不会冒失败表中的无效行或不必要的SQL错误?我错过了一些明显的东西吗?

1 个答案:

答案 0 :(得分:2)

使用INSTEAD OF触发器,而不是AFTER触发器。 EG

    --DROP TABLE IF EXISTS FRIENDSHIP 
    --DROP TABLE IF EXISTS MEMBER
        GO

      CREATE TABLE MEMBER(MemberID int primary key);

      CREATE TABLE dbo.FRIENDSHIP(
             MemberId         INT NOT NULL
           , FriendId         INT NOT NULL
           , DateCreated      DATE NOT NULL DEFAULT CURRENT_TIMESTAMP
      CONSTRAINT pk_friendship PRIMARY KEY( MemberId, FriendId ),
      CONSTRAINT ak_friendship UNIQUE( FriendId, MemberId ),
      CONSTRAINT fk_friendship_member FOREIGN KEY( MemberId ) REFERENCES Member( MemberId ), 
      CONSTRAINT fk_friendship_friend FOREIGN KEY( FriendId ) REFERENCES Member( MemberId ) 
    );

        GO

CREATE OR ALTER TRIGGER friendship_cascade_delete
    ON Member
   INSTEAD OF DELETE
    AS
    BEGIN
        SET NOCOUNT ON;
        DELETE FROM Friendship
         WHERE MemberId IN( SELECT MemberId FROM deleted );

        DELETE FROM Friendship
         WHERE FriendId IN( SELECT MemberId FROM deleted );

        DELETE FROM MEMBER
          WHERE MemberId IN( SELECT MemberId FROM deleted );
    END

    GO 
    INSERT INTO MEMBER(MemberID) values (1),(2),(3)

    INSERT INTO FRIENDSHIP(MemberID, FriendId) values (1,2), (1,3), (3,2)

    go
    select *
    from FRIENDSHIP

    delete from member where MemberID  = 1

    select *
    from FRIENDSHIP