【问题标题】:INSTEAD OF DELETE trigger to prevent deletion if condition is met如果满足条件,INSTEAD OF DELETE 触发器可防止删除
【发布时间】:2019-04-14 15:44:18
【问题描述】:

我正在尝试在我的电影数据库中名为 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;

【问题讨论】:

  • 您的请求不太合理。您是否试图允许从任何给定电影中删除最多一个人的声明?如果我执行delete from cast where actor in ('A','B','C') 之类的语句从电影 1 中删除演员 A 和演员 B,从电影 2 中删除演员 C,那么只有电影 2(演员 C)的删除会成功吗?或者你的意思是试图从已经有 2 个以上演员的电影中删除任何人不会成功?
  • 第二个,所以试图从电影有 2 个或更多演员表的演员表中删除任何人都不会成功。
  • SELECT(或UPDATE)语句的其余部分在哪里,WHERE 子句也属于?这是什么 DBMS?
  • @stickybit SQLServer 风格的语法

标签: sql sql-server triggers sql-delete


【解决方案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 伪表,将其加入演员表的摘要中,并仅选择摘要计数

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

请注意,已对您的数据库做出以下假设:

  • Cast 表有一个 ID 列,每个演员电影都是唯一的
  • CastFilmId 是电影表中的 ID,它对所有参与同一部电影的人重复
  • 如果某部电影的演员没有出演该电影(有可能吗?)我假设他的 CastFilmID 为空。如果这永远不会为空,则可以对查询进行一些简化,但在这种形式中,我打算将演员未分配给电影的记录仍然可以删除

这里要欣赏的关键是运行删除查询的人会在触发器中为您提供 X 行;这些是该人试图删除的行,但您希望在您之前从该数据集之外获得额外知识(例如“有多少其他人与这些人中的每一个人在同一部电影中工作”)可以决定是否删除它们。这就是为什么我们计算那部电影的人数,将其加入被删除人的数据,然后决定是否应该删除该人

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

【讨论】:

  • 哇,非常感谢您的详细解释。它就像一个魅力
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-11
  • 1970-01-01
  • 2011-09-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多