使用MySQL触发器插入新记录后更新表列

时间:2014-03-12 05:37:19

标签: mysql triggers insert sql-update

想象一下,我有一个包含以下字段的MySQL表(tbl_test): id,title,priority
id 会自动递增。插入后,我需要使用与 id 字段相同的值填充优先级字段。
由于我是使用MySQL触发器的新手,请告诉我我要为它编写的内容。我做了一些事情,但我认为事实并非如此:

CREATE TRIGGER 'test' AFTER INSERT ON `tbl_test`
BEGIN
   SET new.priority = new.id;
END

感谢您的协助。

3 个答案:

答案 0 :(得分:16)

您尝试将值设置为列的方式是更新。因为您在插入操作完成后正在执行

您实际上需要before触发器。

要为同一个表分配相同的新自动递增的主键列值,最好从information_schema.tables获取。

示例

delimiter //
drop trigger if exists bi_table_name //

create trigger bi_table_name before insert on table_name
for each row begin
  set @auto_id := ( SELECT AUTO_INCREMENT 
                    FROM INFORMATION_SCHEMA.TABLES
                    WHERE TABLE_NAME='table_name'
                      AND TABLE_SCHEMA=DATABASE() ); 
  set new.priority= @auto_id;
end;
//

delimiter ;

注意 的: 确保您没有任何具有相同名称和/或操作的预定义触发器。 如果有一些,则在创建新的之前删除它们。

答案 1 :(得分:2)

我认为你不能那样做。 AFTER INSERT触发器不能通过发出UPDATE或类似的东西来修改同一个表:

DROP TRIGGER new_tbl_test;

DELIMITER $$

CREATE TRIGGER new_tbl_test 
AFTER INSERT ON tbl_test for each row
begin
UPDATE tbl_test SET priority = new.id WHERE id = new.id;
END $$

DELIMITER ;

它给出了错误,如

ERROR 1442 (HY000): Can't update table 'tbl_test' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.

您可以做的是使用交易:

示例:表格结构如下所示

mysql> show create table tbl_test\G
*************************** 1. row ***************************
       Table: tbl_test
Create Table: CREATE TABLE `tbl_test` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `title` char(30) DEFAULT NULL,
  `priority` int(11) DEFAULT NULL,
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

<强>交易

START TRANSACTION ;
  INSERT INTO tbl_test (title)
    VALUES ('Dr');
  UPDATE tbl_test
    SET `priority` = id
    WHERE id = LAST_INSERT_ID();
COMMIT ;

检查数据

mysql> SELECT * FROM tbl_test;
+----+-------+----------+
| ID | title | priority |
+----+-------+----------+
|  1 | Dr    |        1 |
+----+-------+----------+
1 row in set (0.00 sec)

答案 2 :(得分:0)

我的解决方案。我最初希望在navOrder列中使用表的uniqueID。但是,在触发大容量插入时获取有问题的表的uniqueID的问题太麻烦了。因此,我建立了一种类似于MSSQL的ROWNUMBER功能的机制,其中每行都进行了编号,而与行所在的表或模式无关。尽管我在下面构建的解决方案不会为每个表生成一个数字(如果触发器已添加到每个表中),它解决了我的问题,即每行都需要一个唯一值。

所以,我有2个表,每个表都有一个BEFORE INSERT触发器,该触发器调用用户定义函数(UDF),该函数将获得下一个唯一的序号。

我已经对该功能进行了批量测试(在1个查询中插入1,000行,运行1,000个查询,并行运行全部10次),并且我们将其用于一个网站,该网站每分钟大约有2,000个实时用户,并且插入了大约15,000次一分钟。不是Facebook,而是我们使用的所有东西,它正在为我们工作。

如果运行下面的代码,则会看到回滚不会回滚序列号。

我们没有死锁,也没有重复的值(因为navOrder列的唯一约束不允许重复)。

对我来说,这是一个相对容易理解的解决方案。

CREATE SCHEMA TestLastInsertId;
USE TestLastInsertId;

CREATE TABLE Table1 (
    `tempID`    INT(11)        NOT NULL PRIMARY KEY AUTO_INCREMENT,
    `item`      VARCHAR(256)   NOT NULL,
    `navOrder`  INT(11) UNIQUE NOT NULL,
    `createdAt` TIMESTAMP(6)   NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
    `updatedAt` TIMESTAMP(6)   NULL     DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP(6)
) ENGINE = INNODB DEFAULT CHARSET = utf8 COLLATE = utf8_unicode_ci AUTO_INCREMENT = 1;

CREATE TABLE Table2 (
    `tempID`    INT(11)        NOT NULL PRIMARY KEY AUTO_INCREMENT,
    `item`      VARCHAR(256)   NOT NULL,
    `navOrder`  INT(11) UNIQUE NOT NULL,
    `createdAt` TIMESTAMP(6)   NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
    `updatedAt` TIMESTAMP(6)   NULL     DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP(6)
) ENGINE = INNODB DEFAULT CHARSET = utf8 COLLATE = utf8_unicode_ci AUTO_INCREMENT = 1;

CREATE TABLE IF NOT EXISTS `nav_order_sequence` (
    `navOrderSequence` INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY
) ENGINE = InnoDB AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8;

DELIMITER ;;

CREATE FUNCTION getNextNavOrder()
  RETURNS INT(11) LANGUAGE SQL NOT DETERMINISTIC MODIFIES SQL DATA SQL SECURITY INVOKER
  BEGIN
    INSERT INTO nav_order_sequence() VALUES();
    SET @navOrder = LAST_INSERT_ID();
    DELETE FROM nav_order_sequence WHERE navOrderSequence = @navOrder;
    RETURN @navOrder;
  END;;

CREATE TRIGGER Table1_BEFORE_INSERT BEFORE INSERT ON Table1 FOR EACH ROW
BEGIN
SET NEW.navOrder = getNextNavOrder();
END;;

CREATE TRIGGER Table2_BEFORE_INSERT BEFORE INSERT ON Table2 FOR EACH ROW
BEGIN
SET NEW.navOrder = getNextNavOrder();
END;;

DELIMITER ;

INSERT INTO Table1(item) VALUES('Item1'),('Item2'),('Item3');
INSERT INTO Table2(item) VALUES('Item4'),('Item5'),('Item6');
SELECT * FROM Table1; -- Result 1
SELECT * FROM Table2; -- Result 2
BEGIN;
INSERT INTO Table1(item) VALUES('Item7'),('Item8'),('Item9');
INSERT INTO Table2(item) VALUES('Item10'),('Item11'),('Item12');
SELECT * FROM Table1; -- Result 3
SELECT * FROM Table2; -- Result 4
ROLLBACK;
INSERT INTO Table1(item) VALUES('Item13'),('Item14'),('Item15');
INSERT INTO Table2(item) VALUES('Item16'),('Item17'),('Item18');
SELECT * FROM Table1; -- Result 5
SELECT * FROM Table2; -- Result 6

DROP SCHEMA TestLastInsertId;
Result 1 - Add 3 rows to Table 1 - navOrders 1, 2, and 3.
1   Item1   1   2019-11-02 18:58:28.657690  
2   Item2   2   2019-11-02 18:58:28.657690  
3   Item3   3   2019-11-02 18:58:28.657690  
Result 2 - Add 3 rows to Table 2 - navOrders 4, 5, and 6.
1   Item4   4   2019-11-02 18:58:28.669873  
2   Item5   5   2019-11-02 18:58:28.669873  
3   Item6   6   2019-11-02 18:58:28.669873  
Result 3 - Add 3 more rows to Table 1 - navOrders 7, 8, and 9.
1   Item1   1   2019-11-02 18:58:28.657690  
2   Item2   2   2019-11-02 18:58:28.657690  
3   Item3   3   2019-11-02 18:58:28.657690  
4   Item7   7   2019-11-02 18:58:28.704766  
5   Item8   8   2019-11-02 18:58:28.704766  
6   Item9   9   2019-11-02 18:58:28.704766  
Result 4 - Add 3 more rows to Table 2 - navOrders 10, 11, and 12.
1   Item4   4   2019-11-02 18:58:28.669873  
2   Item5   5   2019-11-02 18:58:28.669873  
3   Item6   6   2019-11-02 18:58:28.669873  
4   Item10  10  2019-11-02 18:58:28.706930  
5   Item11  11  2019-11-02 18:58:28.706930  
6   Item12  12  2019-11-02 18:58:28.706930  

此处发生了回滚,因此删除了两个表的第4、5和6行。

Result 5 - Add 3 more rows to Table 1 after a rollback - navOrders 13, 14, and 15.
1   Item1   1   2019-11-02 18:58:28.657690  
2   Item2   2   2019-11-02 18:58:28.657690  
3   Item3   3   2019-11-02 18:58:28.657690  
7   Item13  13  2019-11-02 18:58:28.727303  
8   Item14  14  2019-11-02 18:58:28.727303  
9   Item15  15  2019-11-02 18:58:28.727303  
Result 6 - Add 3 more rows to Table 1 after a rollback - navOrders 16, 17, and 18.
1   Item4   4   2019-11-02 18:58:28.669873  
2   Item5   5   2019-11-02 18:58:28.669873  
3   Item6   6   2019-11-02 18:58:28.669873  
7   Item16  16  2019-11-02 18:58:28.730307  
8   Item17  17  2019-11-02 18:58:28.730307  
9   Item18  18  2019-11-02 18:58:28.730307  

如果您要删除navOrder上的UNIQUE约束,并将触发器中调用的函数替换为LAST_INSERT_ID(),则会看到重复的值。