I have the following table and update trigger that is made of two parts - an update and a soft delete. A local variable @account_name
is used along with the trigger. On a second update, trigger doesn't fire update correctly. For test purposes, I have WhoTriggered
field in the table, to keep track of what part of the trigger engaged during update:
CREATE TABLE `CC` (
`Id` char(36) NOT NULL,
`Name` char(250) DEFAULT NULL,
`WhoTriggered` char(250) DEFAULT NULL,
`Active` tinyint(1) DEFAULT NULL,
`Deleted` tinyint(1) DEFAULT NULL,
`CreatedBy` char(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
`CreatedAt` datetime DEFAULT CURRENT_TIMESTAMP,
`UpdatedBy` char(100) DEFAULT NULL,
`UpdatedAt` datetime DEFAULT NULL,
`DeletedBy` char(100) DEFAULT NULL,
`DeletedAt` datetime DEFAULT NULL,
PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
DELIMITER $$
CREATE TRIGGER before_CC_update BEFORE UPDATE ON CC
FOR EACH ROW
BEGIN
IF new.deleted = 1 THEN
SET NEW.WhoTriggered = 'SoftDelete';
SET NEW.DeletedBy = @account_name;
SET NEW.DeletedAt = CURRENT_TIMESTAMP();
ELSE
SET NEW.WhoTriggered = 'Update';
SET NEW.UpdatedBy = @account_name;
SET NEW.UpdatedAt = CURRENT_TIMESTAMP();
END IF;
END$$
DELIMITER ;
Insertion, First Update and Marking the record as deleted works with no issues
SET @account_name = 'FirstInsert';
INSERT INTO `test`.`CC` (`Id`, `Name`, `Active`) VALUES ('123', '123', '1');
SET @account_name = 'FirstUpdate';
UPDATE `test`.`CC` SET `Name` = 'Name1' WHERE (`Id` = '123');
SET @account_name = 'MarkDeleted';
UPDATE `test`.`CC` SET `Deleted` = '1' WHERE (`Id` = '123');
However, I also want to track if anyone touches or tries to update record, even if it was marked as deleted, so I ran the second update:
SET @account_name = 'SecondUpdate';
UPDATE `test`.`CC` SET `Name` = 'Name2' WHERE (`Id` = '123');
It gives incorrect update. WhoTriggered
should be Update
, UpdatedBy
should be SecondUpdate
, DeletedBy
should be MarkDeleted
(it's old value). In other words, second update triggered the "deletion" part of the trigger, instead of "update" part of the query.
What is causing this issue and how to correct it ?
The code for your first condition will run whenever new.deleted = 1
. So after you first set deleted = 1
, it will always run this branch. Instead change the condition to:
IF OLD.deleted IS NULL AND NEW.deleted = 1 THEN
Here's a db<>fiddle.
This is not a good use of triggers, especially with the need for your @account_name
variable. It would almost certainly be better managed in your client application code. Just to put in my two-penny worth.