Mysql 触发器在循环前声明

Posted

技术标签:

【中文标题】Mysql 触发器在循环前声明【英文标题】:Mysql Trigger Declare Before Loop 【发布时间】:2016-12-16 18:31:12 【问题描述】:

好吧,伙计们,我在任何地方都找不到这个,但也许我只是不知道该怎么看。我正在使用为每一行调用一个过程的触发器,但我想在 FOR EACH ROW 之前插入一些 DECLARE 语句。原因是我想在循环之前声明一些东西(对于每一行),所以我最终不会为我拥有的每一行一遍又一遍地声明相同的东西。

有人知道怎么做吗?有没有可能?

我的触发器是这样的:

delimiter $$
CREATE TRIGGER tr_inscricao_insert
  AFTER INSERT ON tbl_inscricao

    DECLARE ra_current INT;
    DECLARE done INT DEFAULT FALSE;

FOR EACH row
BEGIN
    CALL pr_atualizar_creditos(new.ra);
END$$
delimiter ;

【问题讨论】:

declare 应该在BEGIN 语句之后。并且不推荐在触发器中调用Procedure。 dev.mysql.com/doc/refman/5.5/en/… 是的,我知道应该在之后。我在问之前是否有办法做到这一点...... 【参考方案1】:

您可以添加另一个层并从包含声明部分并从触发器调用的存储过程中调用您的存储过程。 请参阅此线程以获得一些灵感: Calling a Stored Procedure in a Stored Procedure in MySQL

【讨论】:

我不知道这对我的问题有什么帮助。我想在 FOR EACH ROW 之前做一些 DECLARE 语句。我希望这个语句每个触发器只发生一次,而不是每行一次(因为触发器的其余部分会发生)。【参考方案2】:

MySQL 没有必要的语句级触发器来以标准方式实现此目的,但是我创建了以下解决方法。在 before 触发器中,在第一行之前,它检查 ROW_COUNT 是否为 -1,这意味着尚未插入任何行并将默认值 1 设置为 @x。然后 @x 可以在更新后使用。在 before 触发器中,在第二行之前,当它检查 ROW_COUNT 时,它现在为 1,如果您的 after 触发器插入了更多行,则它现在为 1 或更高,无论哪种方式它都不再是 -1,因此初始化不会再次运行。

DROP TRIGGER record_before_update;
DELIMITER $$
CREATE TRIGGER record_before_update 
    BEFORE UPDATE ON record
    FOR EACH ROW 
BEGIN
    DECLARE y INT;
    SET y = (SELECT ROW_COUNT());
    IF y = -1 THEN 
        SET @x = 1;
    END IF;
END$$
DELIMITER ;

DROP TRIGGER record_after_update;
DELIMITER $$
CREATE TRIGGER record_after_update 
    AFTER UPDATE ON record
    FOR EACH ROW 
BEGIN
    #use @x in something
END$$
DELIMITER ;

请注意,在您的事务中,需要在任何其他更新之前调用使用触发器的语句,否则 ROW_COUNT 不会是 -1。这个例子是为了更新,插入触发器需要同样的东西。

如果看一个真实的例子会有所帮助,下面是我的使用方法。当对不同“区域”中的一堆行进行更新时,它仅通过维护已更新的区域数组来更新单个区域。

DROP TRIGGER record_before_update;
DELIMITER $$
CREATE TRIGGER record_before_update 
    BEFORE UPDATE ON record
    FOR EACH ROW 
BEGIN
    DECLARE y INT;
    SET y = (SELECT ROW_COUNT());
    IF y = -1 THEN 
        SET @x = NULL;
    END IF;
END$$
DELIMITER ;

DROP TRIGGER record_after_update;
DELIMITER $$
CREATE TRIGGER record_after_update 
    AFTER UPDATE ON record
    FOR EACH ROW 
BEGIN
    DELETE FROM record_change where record_id = NEW.id;
    INSERT INTO record_change(record_id, number) VALUES(NEW.id, @x);
    IF @x IS NULL OR FIND_IN_SET(NEW.zone_id, @x) = 0 THEN
      SET @x = CONCAT_WS(',', @x, NEW.zone_id);
        DELETE FROM zone_change where zone_id = NEW.zone_id;
        INSERT INTO zone_change(zone_id, number) VALUES(NEW.zone_id, @x);       
    END IF;

END$$
DELIMITER ;

【讨论】:

以上是关于Mysql 触发器在循环前声明的主要内容,如果未能解决你的问题,请参考以下文章

如何在mysql触发器中声明If语句

Oracle笔记4-pl/sql-分支/循环/游标/异常/存储/调用/触发器

在触发器内循环mysql查询

在 MySQL“删除前”中触发

Mysql触发器用于在插入前检查表中的重复记录

MySQL 触发器声明中缺少“冒号”错误