MySQL之前触发INSERT重复密钥更新 - 手动似乎是错误的?
我与MySQL 5.7的工作:MySQL之前触发INSERT重复密钥更新 - 手动似乎是错误的?
D:\>mysql --version
mysql Ver 14.14 Distrib 5.7.17, for Win64 (x86_64)
按照manual,一个BEFORE INSERT触发器的行为应该是:
一个BEFORE INSERT触发器激活的每一行,随后通过 AFTER INSERT触发器或者触发器BEFORE UPDATE和AFTER UPDATE ,这取决于行是否有重复键。
我认为这意味着BEFORE INSERT被执行,无论是否有重复的键匹配,而AFTER INSERT和UPDATE触发器取决于是否存在键冲突。 This SO重复相同。但是,我没有看到这种行为。这是我做的:
create table testtable (
id integer primary key auto_increment,
nickname varchar(40), -- this is the natural key to be unique indexed
name varchar(40),
uuid varchar(36)); -- this is what I want to assign in the trigger
alter table testtable add unique index testtable_ux (nickname);
create trigger testtable_uid before insert on testtable for each row set
new.uuid=uuid();
-- get some data
insert into testtable (nickname, name) values ('bob', 'Robert'),
('fred', 'Frederick'), ('cha', 'Chauncey');
select * from testtable;
1 bob Robert 06fb18be-f87e-11e6-8e6f-0060737a7c01
2 fred Frederick 06fb1a5d-f87e-11e6-8e6f-0060737a7c01
3 cha Chauncey 06fb1aec-f87e-11e6-8e6f-0060737a7c01
尼斯 - 每个帅哥都有一个独特的UUID。现在确定,根据手册,这个BEFORE INSERT触发器应该被执行,不管是否有重复的键,所以即使当我得到重复的键更新时,UUID也应该被更新 - 对吗?让我们看看:
insert into testtable (nickname, name) values ('fred', 'Alfred')
on duplicate key update name='Alfred';
3 88 16:39:32 ... 2 row(s) affected 0.032 sec
select * from testtable;
1 bob Robert 06fb18be-f87e-11e6-8e6f-0060737a7c01
2 fred Alfred 06fb1a5d-f87e-11e6-8e6f-0060737a7c01
3 cha Chauncey 06fb1aec-f87e-11e6-8e6f-0060737a7c01
嗯,名称已更新。我们来比较一下UUID:
2 fred Frederick 06fb1a5d-f87e-11e6-8e6f-0060737a7c01
2 fred Alfred 06fb1a5d-f87e-11e6-8e6f-0060737a7c01
upsert按照预期执行,但UUID未被重新生成。我用恒定的字符串尝试了这一点,并得到相同的结果。
现在,这正是我想要发生的事情;一个BEFORE INSERT不管upsert的哪个分支被采用,都是无用的,或者至少这种行为似乎更有用。但似乎与手册所说的相反。任何见解?
BEFORE INSERT触发器在重复项上触发。您可以使用日志表对其进行测试。我添加了这样一个表格,将代码和修改触发器来填充该表:
drop table if exists testtable;
create table testtable (
id integer primary key auto_increment,
nickname varchar(40), -- this is the natural key to be unique indexed
name varchar(40),
uuid varchar(36)); -- this is what I want to assign in the trigger
alter table testtable add unique index testtable_ux (nickname);
drop table if exists testlog;
create table testlog (
log_id int primary key auto_increment,
nickname varchar(40),
name varchar(40),
uuid varchar(36)
);
drop trigger if exists testtable_uid;
delimiter //
create trigger testtable_uid before insert on testtable for each row
begin
set new.uuid=uuid();
insert into testlog (nickname, name, uuid) values (new.nickname, new.name, new.uuid);
end //
delimiter ;
insert into testtable (nickname, name) values ('bob', 'Robert'),
('fred', 'Frederick'), ('cha', 'Chauncey');
select * from testtable;
insert into testtable (nickname, name) values ('fred', 'Alfred')
on duplicate key update name='Alfred';
select * from testtable;
select * from testlog;
您将看到testlog
表中有4行。最后一个包含'fred','Alfred'和一个新的UUID。这意味着触发器已被解雇。这也意味着生成了一个新的UUID。但该UUID未分配给testtable.uuid
。您的代码中没有任何内容会告诉您这么做。
如果你想在新的UUID(在触发产生)在对重复部分进行分配,你可以用values(uuid)
存取权限它:
insert into testtable (nickname, name) values ('fred', 'Alfred')
on duplicate key update
name='Alfred',
`uuid`=values(`uuid`);
我明白了。你所说的是触发器正在运行,并且正在填充“新”记录,但它实际上并没有在更新情况下做任何事情,除非你使用values()函数在UPDATE子句中引入它。这就说得通了。谢谢! – fool4jesus
我的猜测:会生成新的'uuid'但不分配。你为什么认为它应该?你可以确切地知道在复制键上应该发生什么:'name ='Alfred''。那么你为什么期望UUID改变? –
@PaulSpiegel谢谢你的想法,但我有“设置”那里。它在初始插入过程中起作用 - 这就是列首先被填充的方式。 – fool4jesus