我正在尝试实施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。是否有可以这样做的新版本?
是否有任何解决方法可以实现此目的?
答案 0 :(得分: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
,但结果会增加。
如果您插入未在pk1
中注册的t2
值,则会失败。 (取消注释demo中的最后一行)在这种情况下,必须在t2
中插入一个新行。由于pk1
中的t2
是PRIMARY KEY,我们可以使用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//