【问题标题】:Trigger to UPDATE and SELECT on same table - ERROR 1235 (42000)在同一张表上触发 UPDATE 和 SELECT - 错误 1235 (42000)
【发布时间】:2017-02-19 17:09:27
【问题描述】:

我正在尝试实现Table with multiple incrementing columns which doesn't reuse deleted column values。此帖子已被How auto-increment within a subset of the table MYSQL 标记为已回答,但是,引用的帖子不符合规定的要求,因为它允许复制子集递增的键。在第一篇文章中,给出了一条评论:

创建一个表来存储每种类型的最后一个 AI 编号。使用触发器 在每次插入时增加它并复制到原始表。 – 保罗 明镜

我认为这是个好主意,并实施了。

-- MySQL Script generated by MySQL Workbench
-- 02/19/17 08:53:34
-- Model: New Model    Version: 1.0
SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL,ALLOW_INVALID_DATES';

-- -----------------------------------------------------
-- Schema mydb
-- -----------------------------------------------------
CREATE SCHEMA IF NOT EXISTS `mydb` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci ;
USE `mydb` ;

-- -----------------------------------------------------
-- Table `mydb`.`t1`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`t1` (
  `pk1` INT NOT NULL,
  `pk2` INT NOT NULL,
  `id2` INT NOT NULL DEFAULT 0,
  PRIMARY KEY (`pk1`, `pk2`))
ENGINE = InnoDB;


-- -----------------------------------------------------
-- Table `mydb`.`t2`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`t2` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `id2` INT NOT NULL,
  PRIMARY KEY (`id`))
ENGINE = InnoDB;


SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
USE `mydb`;

DELIMITER $$
USE `mydb`$$
CREATE TRIGGER `t2_BINS` BEFORE INSERT ON `t2` FOR EACH ROW
begin
UPDATE t1 SET id2=id2+1 WHERE pk1=NEW.pk1 AND pk2=NEW.pk2;
SET NEW.id2=(SELECT id2 FROM t1 WHERE pk1=NEW.pk1 AND pk2=NEW.pk2);
end$$


DELIMITER ;

但是,在执行脚本时,我收到以下错误:

ERROR 1235 (42000) at line 68: This version of MySQL doesn't yet support 'multiple triggers with the same action time and event for one table'

我使用的是 MySQL 5.5.54。有没有新版本可以做到这一点?

是否有任何解决方法来完成此操作?

【问题讨论】:

    标签: mysql triggers


    【解决方案1】:

    您可能在一张表上定义了两个 BEFORE INSERT 触发器。至少那是错误消息所说的。取消注释this demo 中的第二个触发器,您将收到相同的错误消息

    This version of MySQL doesn't yet support 'multiple triggers
    with the same action time and event for one table'
    

    第二个错误是您在错误的表上定义了触发器(或者您在触发器中混淆了表)。您的触发器位于 t2,但您正尝试访问来自 t1 (NEW.pk1) 的列。所以你会得到以下错误信息:

    Unknown column 'pk1' in 'NEW'
    

    http://sqlfiddle.com/#!9/1515abb(取消注释触发器中的行。)

    但是 - 即使解决了这个问题,逻辑看起来也不正确。您可能想要的工作版本可能是:

    CREATE TABLE IF NOT EXISTS `t1` (
      `pk1` INT NOT NULL,
      `pk2` INT NOT NULL DEFAULT 0,
      PRIMARY KEY (`pk1`, `pk2`))
    ENGINE = InnoDB;
    
    CREATE TABLE IF NOT EXISTS `t2` (
      `pk1` INT NOT NULL,
      `last_pk2` INT NOT NULL,
      PRIMARY KEY (`pk1`))
    ENGINE = InnoDB;
    
    DELIMITER //
    
    CREATE TRIGGER `t1_BINS` BEFORE INSERT ON `t1` FOR EACH ROW
    begin
      UPDATE t2 SET last_pk2=last_pk2 + 1 WHERE pk1=NEW.pk1;
      SET NEW.pk2=(SELECT last_pk2 FROM t2 WHERE pk1=NEW.pk1);
    end//
    
    DELIMITER ;
    

    正如您在demo 中看到的,第二次插入没有指定pk2,但在结果中增加了。

    但是,如果您插入未在 t2 中注册的 pk1 值,这将失败。 (取消注释demo 中的最后一行)在这种情况下,必须将新行插入t2。由于pk1t2 中的主键,我们可以使用INSERT .. ON DUPLICATE KEY UPDATE .. 语法:

    CREATE TRIGGER `t1_BINS` BEFORE INSERT ON `t1` FOR EACH ROW
    begin
      INSERT INTO t2 (pk1, last_pk2) values (NEW.pk1, 1)
        ON DUPLICATE KEY UPDATE last_pk2 = last_pk2 + 1;
      SET NEW.pk2=(SELECT last_pk2 FROM t2 WHERE pk1=NEW.pk1);
    end//
    

    http://sqlfiddle.com/#!9/79eeea/1

    现在最后一步是让它并发保存。我们必须防止两个并发线程/会话为t2.last_pk2 读取相同的值。因此,写作和阅读应该在一个语句中完成。我们可以使用会话变量或LAST_INSERT_ID() 来做到这一点:

    CREATE TRIGGER `t1_BINS` BEFORE INSERT ON `t1` FOR EACH ROW
    begin
      INSERT INTO t2 (pk1, last_pk2) values (NEW.pk1, @last_pk2 := 1)
        ON DUPLICATE KEY UPDATE last_pk2 = @last_pk2 := (last_pk2 + 1);
      SET NEW.pk2 = @last_pk2;
    end//
    

    http://sqlfiddle.com/#!9/dc235a/1

    CREATE TRIGGER `t1_BINS` BEFORE INSERT ON `t1` FOR EACH ROW
    begin
      INSERT INTO t2 (pk1, last_pk2) values (NEW.pk1, LAST_INSERT_ID(1))
        ON DUPLICATE KEY UPDATE last_pk2 = LAST_INSERT_ID(last_pk2 + 1);
      SET NEW.pk2 = LAST_INSERT_ID();
    end//
    

    http://sqlfiddle.com/#!9/86ed740/1

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-20
      • 2015-09-02
      • 1970-01-01
      • 1970-01-01
      • 2010-12-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多