想象一下,我有一个包含以下字段的MySQL表(tbl_test): id,title,priority 。
id 会自动递增。插入后,我需要使用与 id 字段相同的值填充优先级字段。
由于我是使用MySQL触发器的新手,请告诉我我要为它编写的内容。我做了一些事情,但我认为事实并非如此:
CREATE TRIGGER 'test' AFTER INSERT ON `tbl_test`
BEGIN
SET new.priority = new.id;
END
感谢您的协助。
答案 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()
,则会看到重复的值。