简体   繁体   中英

INSTEAD OF DELETE trigger to prevent deletion if condition is met

I am trying to set up an INSTEAD OF DELETE trigger on a table called Cast in my Movies database. I want it to prevent the deletion of a row if the CastFilmID count is greater than 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;
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;

You forgot to actually do a delete inside your trigger, so nothing would ever be deleted from your table.

I've flipped the logic around: for all the records you attempt to delete, only records relating to an actor who shares a film with no other actor, can be deleted

To do this we take the list of people the app(for example) tried to delete - deleted d pseudotable, join it onto a summary of the cast table, and pick only records where the summary counts < 2 actors:

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

Suppose I say delete from cast where id in ('KEANU','JARAN','JESUS') - this tries to delete people from every film we know. It will realize a deleted pseudotable of:

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

Left Joined onto this are the film counts:

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

The WHERE clause removes KEANU from the results, because he works on a film of 3 actors (including himself)

The following 2 records of the original requested 3 are deleted ( DELETE FROM cast WHERE ID IN (...this list...) :

Cast.ID
JARAN
JESUS

Please note that the following assumptions about your db have been made:

  • The Cast table has an ID column that is unique per actor-film
  • The CastFilmId is the ID from the film table, and it repeats for everyone who works on the same film
  • When an actor for a film is not cast in that film (is it possible?) I've assumed his CastFilmID is null. If this will never be null some simplifications could be made to the query, but in this form I intended that records where the actor is not assigned to a film, can still be deleted

The critical thing to appreciate here is that someone running a delete query will give you X number of rows in your trigger; those are the rows the person is trying to delete, but you want extra knowledge from outside that set of data (eg "how many other people work on the same films as each of these people") before you can decide whether to delete them or not. This is why we count the number of people on that film, join it in to the data of the person being deleted, and THEN decide if that person should be deleted

Really, this sort of magic should be done in the front end. Things get very confusing when you tell a DB to delete something and it doesn't. Equally yu have to be mindful that DELETE queries can delete hundreds of rows at a time, so you can't take the simplistic approach of "the delete will only ever try to remove one cast row" - you have to work on these things as sets of data, join them to other sets of data, and come up with a set of data that is to be deleted

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM