2017-02-19 36 views
1

我試圖執行Table with multiple incrementing columns which doesn't reuse deleted column values。這篇文章被標記爲已被How auto-increment within a subset of the table MYSQL回答,但是,所引用的帖子不符合所述要求,因爲它允許子集遞增鍵被複制。在第一篇文章中,給出了一條評論:觸發更新並在同一個表上選擇 - 錯誤1235(42000)

Create a table that will store last AI numbers per type. Use a trigger to increment it on every insert and copy to the original table. – Paul Spiegel

我認爲這是一個好主意,並付諸實施。

-- MySQL Script generated by MySQL Workbench 
-- 02/19/17 08:53:34 
-- Model: New Model Version: 1.0 
SET @[email protected]@UNIQUE_CHECKS, UNIQUE_CHECKS=0; 
SET @[email protected]@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0; 
SET @[email protected]@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 [email protected]_SQL_MODE; 
SET [email protected]_FOREIGN_KEY_CHECKS; 
SET [email protected]_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 54年5月5日。有新版本可以這樣做嗎?

是否有任何解決方法來實現這一目標?

回答

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,但您嘗試訪問t1NEW.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我們可以使用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