Search code examples
mysqltriggersdistinct

MySQL - Trigger to prevent deletion via connected tables


I have three PK columns (staff, the_date and work_time), two of which are reliant on each other: work_time and the_date.

PK staff is linked to Staff table, and PK the_date and work_time is linked to Company table. But all three PK described are in Admission table.

I need to make a trigger that prevents deletion of a staff, if the work_time and the_date are the remaining one for the table Admission.

For example:

ROW 1: staff: 2 | the_date: 2012-01-20 | work_time : 13:20:02
ROW 2: staff: 3 | the_date: 2012-01-20 | work_time : 13:20:02
ROW N: ............

To clarify, each time and date can be the same but can have many UNIQUE staffs working there at the same time.

From the example above, if I tried to delete staff 3 (ROW 2), then no problem - that is permitted. However, if I tried to delete again, but this time for staff 2 (ROW 1) then the trigger would fire and prevent me from deleting that remaining staff (row).

I'm new to triggers, but I had a crack at it but wasn't able to make it work. From my interpretation on how the code goes is: IF the_date and work_time are DISTINCT then DON'T DELETE ELSE DELETE.

Here's what I did:

CREATE TRIGGER preventLastStaffDeletion
BEFORE DELETE 
ON Admission 
FOR EACH ROW
BEGIN
SELECT DISTINCT the_date, work_time FROM Admission;
END

Thanks in advance.


Solution

  • From the trigger documentation:

    The trigger cannot use statements that explicitly or implicitly begin or end a transaction such as START TRANSACTION, COMMIT, or ROLLBACK.

    So usually this would be not possible. What you can do is to force an error in your trigger when you want to fail the whole transaction: e.g.

    CREATE TRIGGER t1 BEFORE DELETE ON table1
    FOR EACH ROW
    BEGIN
          IF (failCondition) THEN
               SELECT 1/0 FROM table1 LIMIT 1
          END IF;
    END
    

    This would trigger a error and rollback the whole transaction

    EDIT:

    So for your problem this would be something like this

    CREATE TRIGGER preventLastStaffDeletion BEFORE DELETE ON Admission
    FOR EACH ROW
    BEGIN
          DECLARE remaining INT DEFAULT 0;
          SET remaining := (SELECT COUNT(staff) FROM Admission WHERE the_date = OLD.the_date AND work_time = OLD.work_time );
          IF remaining = 1 THEN
               SELECT 1/0 FROM Admission LIMIT 1
          END IF;
    END
    

    Didn't test so excuse syntax errors, but the idea should be clear.

    Allows deletion of staff with this work time at this date till there is only one left

    EDIT 2 Re-read your question and updated the fail condition