无法使用MySQL触发器删除行

czq61nw1  于 2023-02-11  发布在  Mysql
关注(0)|答案(1)|浏览(122)

我在MySQL中有一个触发器

DELIMITER $$ 
CREATE TRIGGER trigger2
BEFORE INSERT ON participated FOR EACH ROW
 BEGIN    
 IF((SELECT COUNT(*) FROM participated WHERE driver_id = NEW.driver_id) > 3) THEN 
     DELETE FROM accident WHERE report_no = NEW.report_no;         
SIGNAL SQLSTATE '45000' SET message_text = "Driver is already involved in 3 accciddents"; 
END IF; 
END;$$ 
DELIMITER ;

首先将事故报告插入事故表。在插入参与表之前,如果涉及参与3次以上事故的驾驶员,则必须给出警告,并删除事故表中的驾驶员数据。

'accident' and 'participated' are the two tables.

 accident(report_no,date,location);
  participated(driver_id,reg_no,report_no,amount);

例如:

insert into accident values(34,"2022-04-05","bangalore");

 insert into participated values("D1","KA-09-MM-5644",34,20000);

 ERROR 1644 (45000): Driver is already involved in 3 accciddents

警告起作用,但未删除事故表中的行。事故表中仍有report_no 34的行

xwbd5t1u

xwbd5t1u1#

Mysql触发器中的body部分就像一个ALL-OR-NOTHING事务。这意味着里面的每个查询都必须成功,否则整个过程都会被撤消。通过使用SIGNAL SQLSTATE '45000' SET message_text,故意引发一个错误,它会回滚到目前为止发生的每一件事,并返回一条消息。注意,INSERT语句本身会因为引发的错误而被取消。当然,可以通过在触发器的开头声明一个continue处理程序来忽略错误。

BEGIN
declare continue handler for SQLSTATE '45000' begin end;    
 IF((SELECT COUNT(*) FROM participated WHERE driver_id = NEW.driver_id) > 3) THEN 
     DELETE FROM accident WHERE report_no = NEW.report_no;         
SIGNAL SQLSTATE '45000' SET message_text = "Driver is already involved in 3 accciddents"; 
END IF; 
END

这将确保在遇到SQLSTATE '45000'后继续运行。但是,message_text是IGNORED,因为它只用于处理警告/错误,而不是用于continue处理程序。遗憾的是,我们不能使用触发器返回结果集。因此,如果我们在SIGNAL语句后添加SELECT语句或类似语句,将弹出一个错误:

select "Driver is already involved in 3 accciddents" as a warning; 
-- OR
show warnings;
-- Error Code: 1415. Not allowed to return a result set from a trigger

如果我们真的需要一条消息显示出来,我们可以考虑使用一个过程来绕过触发器所强加的限制:

DELIMITER $$ 
CREATE TRIGGER trigger2
BEFORE INSERT ON participated FOR EACH ROW
 BEGIN    
 IF((SELECT COUNT(*) FROM participated WHERE driver_id = NEW.driver_id) > 3) THEN 
     DELETE FROM accident WHERE report_no = NEW.report_no;         
SET @warning = "Driver is already involved in 3 accciddents"; -- here we don't really need a SIGNAL statement. Just creating a user variable is adequate.
else set @warning=null;
END IF; 
END$$

create procedure insert_participated (d_id varchar(20),rg_no varchar(20),rp_no int,amt int)
begin
insert into participated values(d_id,rg_no,rp_no,amt);
if @warning is not null then 
select @warning as warning;
end if;
end $$ 
DELIMITER ;

通过使用过程,我们可以显示消息。如果我们直接使用insert语句(当我们忘记使用过程时),触发器的操作仍然适用。因此,我们可以考虑添加INSERT语句来填充审计表以供将来参考。

相关问题