Reputation: 51
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;
Upvotes: 1
Views: 4495
Reputation: 74605
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 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 (e.g. "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
Upvotes: 2