【问题标题】:MySQL - Trigger for updating same table after insertMySQL - 插入后更新同一张表的触发器
【发布时间】:2012-10-13 22:50:11
【问题描述】:

这就是我想要做的:

ACCOUNTS 表中有新的INSERT 时,我需要通过设置status='E' 来更新ACCOUNTS 中的行,其中pk = NEW.edit_on 表示特定(旧)帐户具有已编辑。

DELIMITER $$

DROP TRIGGER IF EXISTS `setEditStatus`$$
CREATE TRIGGER `setEditStatus` AFTER INSERT on ACCOUNTS
FOR EACH ROW BEGIN
    update ACCOUNTS set status='E' where ACCOUNTS.pk = NEW.edit_on ;
END$$

DELIMITER ;

要求不是我操作 新插入的列,而是 已经存在列与pk = NEW.edit_on

但是,我无法更新同一张表:Can't update table ACCOUNTS ... already used by the statement that invoked this trigger

请提出解决方法

PS:我已经经历过Updating table in trigger after update on the same tableInsert into same table trigger mysqlUpdate with after insert trigger on same tablemysql trigger with insert and update after insert on table,但他们似乎没有回答我的问题。

编辑

ACCOUNTS表:

CREATE TABLE  `ACCOUNTS` (
  `pk` bigint(10) unsigned NOT NULL AUTO_INCREMENT,
  `user_id` bigint(9) unsigned NOT NULL,
  `edit_on` bigint(10) unsigned DEFAULT NULL,
  `status` varchar(1) NOT NULL DEFAULT 'A',
  PRIMARY KEY (`pk`) USING BTREE) ENGINE=InnoDB AUTO_INCREMENT=2147483726 DEFAULT CHARSET=latin1

【问题讨论】:

  • 如何唯一标识ACCOUNTS 中的行?如果edit_on是你的主键,那你怎么能插入重复呢?
  • 我已编辑问题以包含表格结构。请看。
  • 如果edit_on = 123 代表pk = 456 所在的行,这意味着456123 的编辑。因此,status 应更新为 'E'123
  • 您的架构中没有 status 列。
  • 哎呀..对不起,我的错。请立即查看编辑

标签: mysql database-trigger


【解决方案1】:

您似乎无法在触发器中完成所有这些操作。根据documentation

在存储的函数或触发器中,不允许修改已被调用函数或触发器的语句使用(用于读取或写入)的表。

根据this answer,看来你应该:

创建一个存储过程,插入/更新目标表,然后更新其他行,所有这些都在一个事务中。

使用存储过程,您将手动提交更改(插入和更新)。我没有在 MySQL 中这样做,但 this post 看起来是一个很好的例子。

【讨论】:

  • 这是否意味着我必须从触发器调用存储过程?
  • 不,我相信您将原始的INSERT 查询移动到存储过程中,并调用proc而不是查询。这是 MySQL 的语法:dev.mysql.com/doc/refman/5.0/en/call.html
  • 我在这里有点困惑。您是指将原始插入移动到过程中并使用触发器进行更新,还是将整个逻辑移动到存储过程中?
  • 将两个语句(插入 + 更新)放在一个存储过程中。如果语句执行成功,那么你commit,否则rollback 改变。
  • 好消息。我已经实现了。它工作正常。除了我无法在我的 JDBC 模板中获取状态(如果 SP 更改了任何行)之外:(
【解决方案2】:

这就是我如何在插入时更新同一个表中的一行

activationCodeemail 是表 USER 中的行。 在插入时,我没有为activationCode 指定值,它将由 MySQL 动态创建。

username 更改为您的MySQL 用户名,将db_name 更改为您的数据库名称。

CREATE DEFINER=`username`@`localhost` 
       TRIGGER `db_name`.`user_BEFORE_INSERT` 
       BEFORE INSERT ON `user` 
       FOR EACH ROW
         BEGIN
            SET new.activationCode = MD5(new.email);
         END

【讨论】:

  • 非常好的解决方案!!! pjama 建议的解决方案很好,但它不适合我的情况,而这个效果很好,不需要存储过程
  • 是的,重要的是不要写 UPDATE ACCOUNTS 部分,这是 MYSQL 阻止的。
  • 这让我投了反对票,因为它完全忽略了明确声明的要求,即更新应该作用于不同的记录,而不是新插入的记录。
  • 试过了,它对我不起作用 CREATE TRIGGER add_comment_hash_after_insert BEFORE INSERT ON comments FOR EACH ROW BEGIN SET new.comment_hash = 'aa';结束;
  • 嘿不错的解决方案!它很简单,对我来说很好用,谢谢分享。
【解决方案3】:

遇到了同样的问题,但必须使用即将输入的 id 更新列,因此您可以在没有 id 之前和之后进行更新,所以我做了这个技巧

DELIMITER $$
DROP TRIGGER IF EXISTS `codigo_video`$$
CREATE TRIGGER `codigo_video` BEFORE INSERT ON `videos` 
FOR EACH ROW BEGIN
    DECLARE ultimo_id, proximo_id INT(11);
    SELECT id INTO ultimo_id FROM videos ORDER BY id DESC LIMIT 1;
    SET proximo_id = ultimo_id+1;
    SET NEW.cassette = CONCAT(NEW.cassette, LPAD(proximo_id, 5, '0'));
END$$
DELIMITER ;

【讨论】:

  • 我不得不说,这是解决这个问题的一种非常粗略的方法,因为它的前提是没有添加/删除条目(因此从 MAX(id) + 1会产生)。无论如何,这是我发现完成我需要的唯一解决方案,我觉得我可以在这个前提下存钱。我正在尝试(由于从 PHP 迁移到 Django)将我的所有主键从 TABLENAME_id 重命名为 id 而不会破坏我的应用程序。好东西。
  • 这让我投了反对票,因为它完全忽略了明确声明的要求,即更新应该作用于不同的记录,而不是新插入的记录。
【解决方案4】:

在最后一个条目上;这是另一个技巧:

SELECT AUTO_INCREMENT FROM information_schema.tables WHERE table_schema = ... and table_name = ...

【讨论】:

  • 你能在编辑中解释一下你的答案吗?谢谢。
【解决方案5】:

相反,您可以在插入之前使用并获取特定表的最大 pkid,然后更新最大 pkid 表记录。

【讨论】:

    【解决方案6】:
    DELIMITER $$
    
    DROP TRIGGER IF EXISTS `setEditStatus`$$
    CREATE TRIGGER `setEditStatus` **BEFORE** INSERT on ACCOUNTS
    FOR EACH ROW BEGIN
    
        SET NEW.STATUS = 'E';
    
    END$$
    
    DELIMITER ;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-12-18
      • 2023-04-09
      • 2011-07-17
      • 2011-10-19
      • 2016-10-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多