0

我有一张表 Universities 和一张表 Cities。它们之间存在 am:n 关系,因此该关系保存在另一个名为 CityUniversities 的表中。现在我想编写一个触发器,当从 Universities 中删除一所大学时,它会删除表 Cities 和 Universities 之间的所有关系。但是它不起作用。尝试删除大学时,我总是收到以下错误消息:

“消息 547,级别 16,状态 0,第 2 行 DELETE 语句与 REFERENCE 约束“FK_CityUniversities_Universities”冲突。冲突发生在数据库“Alumni_Dev”、表“dbo.CityUniversities”、列“UniversityId”中。语句已终止。”

这就是我已经实现并成功执行的触发器(对于表 Universities):

USE [Alumni_Dev]
GO
/****** Object:  Trigger [dbo].[deleteUni]    Script Date: 05/02/2012 11:42:43 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER TRIGGER [dbo].[deleteUni]
ON  [dbo].[Universities] 
FOR DELETE
AS 
DECLARE @UniId int
SELECT @UniId = (SELECT UniversityId FROM deleted)
BEGIN
--Remove constraints
DELETE FROM dbo.CityUniversities WHERE UniversityId = @UniId;
END  

我已经将我的解决方案与几个参考文献进行了比较,但是我找不到任何可能出错的地方。可能是其中一个受影响的表中有任何错误的设置吗?

我很乐意听到任何建议。


我终于用以下触发器解决了我的问题(感谢 Nikola):

ALTER TRIGGER [dbo].[deleteUni]
ON  [dbo].[Universities] 
INSTEAD OF DELETE
AS 
DECLARE @UniId int
SELECT @UniId = UniversityId FROM deleted
BEGIN
--Remove constraints
DELETE FROM dbo.CityUniversities WHERE UniversityId = @UniId;
DELETE FROM dbo.Universities WHERE UniversityId = @UniId;
END
4

1 回答 1

4

触发器不能用于从其他表中删除孤立记录,因为在执行触发器之前会检查约束。您应该改为设置ON DELETE CASCADE

如果您想在删除之前执行一些检查,您也可以使用INSTEAD OF触发器,但不要忘记delete Universities where ...在触发器末尾添加以实际删除记录。

关于触发器的两点:

  • 在触发器主体的开头添加SET NOCOUNT ON以避免触发器内部的 sql 语句更改调用代码时可能需要的“受影响的行”的值,
  • 不要将已删除和插入的表视为仅包含一条记录。当您尝试删除两所大学时,会有令人讨厌的惊喜。您应该加入使用已删除或插入表的表,将它们用作过滤器,或者使用存在:

    delete dbo.CityUniversities
      from dbo.CityUniversities
     inner join deleted
        on dbo.CityUniversities.UniversityId = deleted.UniversityId 
    

或者

delete dbo.CityUniversities
 where exists (select null
                 from deleted
                where deleted.UniversityId =dbo.CityUniversities.UniversityId)

哦,还有

SELECT @UniId = (SELECT UniversityId FROM deleted)

相当于:

SELECT @UniId = UniversityId FROM deleted
于 2012-05-02T10:03:52.843 回答