如果满足条件,则INSTEAD OF DELETE触发器可防止删除

时间:2019-04-14 15:44:19

标签: sql sql-server triggers sql-delete

我试图在我的电影数据库中名为Cast的表上设置INSTEAD OF DELETE触发器。如果CastFilmID计数大于2,我希望它防止删除行

CREATE TRIGGER Prevent_Cast_Delete ON Cast
INSTEAD OF DELETE 
AS
WHERE COUNT CastFilmID > 2
RAISERROR ('Contains more than 2 cast memebers',16,1)
ROLLBACK TRAN
RETURN;

1 个答案:

答案 0 :(得分:1)

CREATE TRIGGER Prevent_Cast_Delete ON Cast
INSTEAD OF DELETE 
AS 
BEGIN
  DELETE FROM Cast WHERE id IN (
    --Identify only people who work in films with 0 or 1 cast members
    SELECT d.id 
    FROM
      --The list of people we try to delete (request from elsewhere)
      Deleted d 
      LEFT OUTER JOIN 
      --This query counts the cast for every film 
      (SELECT CastFilmID, COUNT(*) as CastCount FROM Cast GROUP BY CastFilmId) c 
      ON
        c.CastFilmID = d.CastFilmID
    --This where clause reduces the list of actor IDs we try to delete, to actually
    --just those actors who are in a film of 1 cast member
    WHERE c.CountCast < 2 OR d.CastFilmID IS NULL
  );
END;

您忘记在触发器内实际执行删除操作,因此不会从表中删除任何内容。

我已经颠倒了逻辑:对于您尝试删除的所有记录,只能删除与没有其他演员共享电影的演员有关的记录

为此,我们将应用程序试图删除的人员列表(例如,伪表-deleted d伪表,加入到强制转换表的摘要中,并仅选择摘要计数少于2个参与者的记录) :

Cast.ID, Cast.CastFilmID
KEANU, MATRIX
LAURE, MATRIX
HUGOW, MATRIX
JARAN, MOBYDI
JESUS, null

假设我说delete from cast where id in ('KEANU','JARAN','JESUS')-这试图从我们认识的每部电影中删除人物。它将实现以下内容的deleted伪表:

Cast.ID, Cast.CastFilmID
KEANU, MATRIX
JARAN, MOBYDI
JESUS, null

左上角是电影计数:

Cast.ID, Cast.CastFilmID, CastCount
KEANU, MATRIX, 3
JARAN, MOBYDI, 1
JESUS, null, null

WHERE子句将KEANU从结果中删除,因为他正在拍摄3名演员(包括他本人)的电影

原始请求的3条记录中的以下2条记录被删除(DELETE FROM cast WHERE ID IN (...this list...)

Cast.ID
JARAN
JESUS

请注意,关于数据库的假设如下:

  • 演员表具有一个ID列,该ID列对于每个演员电影都是唯一的
  • CastFilmId是电影表中的ID,对于在同一部电影上工作的每个人都会重复使用
  • 当电影中的演员没有在电影中放映(可能吗?)时,我假设他的CastFilmID为null。如果永远不会为空,可以对查询进行一些简化,但是以这种形式,我打算记录仍未删除演员的电影记录,仍然可以删除

这里要理解的关键是,运行删除查询的人将在触发器中给您X的行数。这些是该人要删除的行,但在此之前,您想从该组数据之外额外的知识(例如“有多少其他人与每个人一起制作同一部电影”)可以决定是否删除它们。这就是为什么我们计算那部电影的人数,将其加入要删除的人的数据,然后决定是否应该删除该人的原因

真的,这种魔术应该在前端完成。当您告诉数据库删除某件事时,事情变得非常混乱。同样,您还必须注意DELETE查询一次可以删除数百行,因此您不能采用“删除只会尝试删除一个强制转换行”的简单方法-您必须像处理这些事情一样数据集,将它们与其他数据集结合,并提出一组要删除的数据