MySQL中replace into详解、批量更新、不存在插入存在则更新、replace into的坑

MySQL中replace into详解、批量更新、不存在插入存在则更新、replace into的坑

以下内容基于mysql 8.0版本进行讲解。

into与on key 在一定程度上都能实现无记录时插入,有记录时更新这个需求。但是强烈推荐使用on key 原因见下方两者的区别。 into的坑太多,若要使用请详细阅读本文。

一、 into原理

into 跟 功能类似,不同点在于: into 首先尝试插入数据到表中, 1. 如果发现表中已经有此行数据(根据主键或者唯一索引判断)则先删除此行数据,然后插入新的数据。 2. 否则,直接插入新数据。

要注意的是:插入数据的表必须有主键或者是唯一索引!否则的话, into与 into功能一致,会直接插入数据,这将导致表中出现重复的数据。

如果归纳一下 INTO 语句的执行规则,基本会有以下几种情况:

当表没有主键和唯一键时, INTO 相当于普通的 操作; 记录事件为 ;返回影响行数为 的数量。当表有主键没有唯一键时, INTO 插入记录与主键冲突时会进行 + 操作; 记录事件为 ;返回影响行数为 + 的数量;如果主键自增,则 值不变。当表有唯一键没有主键时, INTO 插入记录与唯一键冲突时会进行 + 操作; 记录事件为 ;返回影响行数为 + 的数量。当表同时存在主键和唯一键时, INTO 插入记录与主键冲突的时候进行 + 操作; 记录事件为 +;返回影响行数为 + 的数量。如果主键自增,则 值不变。当表同时存在主键和唯一键时, INTO 插入记录与唯一键冲突的时候进行 + 操作; 记录事件为 ;返回影响行数为 + 的数量。如果主键自增,则新插入的这条记录的主键会变成最新 的值,而对应的 值会 +1。当表同时存在主键和唯一键时, INTO 插入记录与一条记录主键和一条记录唯一键都冲突的时候进行 + 操作; 记录事件为 +;返回影响行数为 *2+ 的数量。

第五点会有副作用:见本文《3.1.3、有主键有唯一索引且唯一索引冲突(有坑)》

第六点会有副作用:见本文《3.1.4、有主键有唯一索引且与一条主键冲突与另一条唯一键冲突(有坑)》

总结

以下总结 into时可能会遇到的场景

pk:主键 uk:唯一索引

场景

into时相当于

into在中的表现形式

返回影响行数

无pk无uk

行数

场景

into时相当于

into在中的表现形式

返回影响行数

pk冲突

+

+行数

pk不冲突

行数

场景

into时相当于

into在中的表现形式

返回影响行数

uk冲突

+

+行数

场景

into时相当于

into在中的表现形式

返回影响行数

pk冲突 uk不冲突

+

+

+行数

pk不冲突 uk冲突

+

+行数

pk冲突 uk冲突

+

+

+行数

pk不冲突 uk不冲突

行数

二、 into的三种形式

1. replace into tbl_name(col_name, ...) values(...)
2. replace into tbl_name(col_name, ...) select ...
3. replace into tbl_name set col_name=value, ...

第一种形式相似于 into的用法,

第二种 的用法也相似于 ,这种用法并不必定要求列名匹配,事实上,MYSQL甚至不关心返回的列名,它需要的是列的位置。例如, into tb1( name, title, mood) rname, , rmood from tb2; 这个例子使用 into从 tb2中将全部数据导入tb1中。

第三种 set用法相似于 set用法,使用一个例如“SET = + 1”的赋值,则对位于右侧的列名称的引用会被做为()处理。所以,该赋值至关于SET = () + 1。

前两种形式用的多些。其中 “into” 关键字能够省略,不过最好加上 “into”,这样意思更加直观。另外,对于那些没有给予值的列,MySQL 将自动为这些列赋上默认值。

三、 into 使用案例 3.1、 into 3.1.1、只有主键且主键冲突

当只有主键且主键冲突时,会执行+操作

如下sql:

drop table if exists user_test;
create table user_test(
	id int primary key auto_increment comment '主键',
	name varchar(30)  not null comment '姓名',
	update_time timestamp on update CURRENT_TIMESTAMP comment '更新时间'
) comment '测试表';
insert into user_test(name,update_time) value ('zhangsan','2000-01-01 00:00:00');

此时执行 into

replace into user_test(id,name) value (1,'zhangsan');

上图可以看出执行 into之后,返回的受影响条数是2,且的字段被更新为空了。由此证明 into时当只有主键且主键冲突时执行了+操作。

注意: 当时间字段设置自动更新后MySQL中replace into详解、批量更新、不存在插入存在则更新、replace into的坑,若没有设置默认值, into更新时需要手动赋予时间字段,否则会插入为空。

3.1.2、有主键有唯一索引且主键冲突

当有主键有唯一索引且主键冲突时,会执行+操作

drop table if exists user_test;
create table user_test(
	id int primary key auto_increment comment '主键',
	name varchar(30) unique not null comment '姓名',
	update_time timestamp on update current_timestamp comment '更新时间'
) comment '测试表';
insert into user_test(name,update_time) value ('zhangsan','2000-01-01 00:00:00');
replace into user_test(id,name) value (1,'lisi');

上图可以看出执行 into之后,返回的受影响条数是2,且的字段被更新为空了。由此证明 into时当有主键有唯一索引且主键冲突时执行了+操作。

3.1.3、有主键有唯一索引且唯一索引冲突(有坑)

当有主键有唯一索引且唯一索引冲突时,会执行+操作,且自增1

drop table if exists user_test;
create table user_test(
	id int primary key auto_increment comment '主键',
	name varchar(30) unique not null comment '姓名',
	update_time timestamp on update current_timestamp comment '更新时间'
) comment '测试表';
insert into user_test(name,update_time) value ('zhangsan','2000-01-01 00:00:00');

此时执行 into语句

replace into user_test(name) value ('zhangsan');

上图可以看出执行 into之后,返回的受影响条数是2,且的字段被更新为空了。由此证明 into时当有主键有唯一索引且唯一索引冲突时执行了+操作。

注意: 唯一索引冲突时会带来副作用,主键id被改变了。由于主键设置了自增,所以当唯一索引冲突时导致的值自增1。

3.1.4、有主键有唯一索引且与一条主键冲突与另一条唯一键冲突(有坑)

当有主键与唯一索引时,若 into与其中一条主键冲突、与另一条记录唯一索引冲突,此时执行+操作。注意:此时受影响的条数是3,且会删除两条数据,可能会有坑

drop table if exists user_test;
create table user_test(
	id int primary key auto_increment comment '主键',
	name varchar(30) unique not null comment '姓名',
	update_time timestamp on update current_timestamp comment '更新时间'
) comment '测试表';
insert into user_test(id,name,update_time) values
(1,'zhangsan','2000-01-01 00:00:00'),
(2,'lisi','2000-01-01 00:00:00');
replace into user_test(id,name) value (1,'lisi');

上图可以看出执行 into之后mysql replace into,返回的受影响条数是3。

注意: 在该场景下会删除2条数据,然后插入1条数据,所以可能会造成坑,需要特别注意。

3.2、 into

语法类似 into

示例:
replace into t(id, update_time) select 1, now();
replace into tb1( name, title, mood) select rname, rtitle, rmood from tb2;

3.3、 into set

表结构如下:

drop table if exists user_test;
create table user_test(
	id int primary key auto_increment comment '主键',
	name varchar(30) unique not null comment '姓名',
	age int default 2 comment '年龄',
	sex varchar(10) comment '性别:男、女'
) comment '测试表';

其中: name为唯一索引,age默认值是2

3.3.1、唯一索引不重复

执行以下sql插入第一条数据

replace into user_test set name = 'zhangsan',age = age+1, sex = '男';

可以看到age=3是因为age=(age)+1,默认age=2然后又+1所以是3;若age字段建表时没有设置默认值则上述sql执行完后age为null。

3.3.2、唯一索引重复

接着上面的示例mysql replace into,运行以下sql

replace into user_test set name = 'zhangsan',age = age+1;

我们看到id=1的数据被删除了,新增了一条id=2的数据;它的sex字段的值没有继承第一条数据的值,age属性的值也只是由默认值决定,与上一条的值无关。

由此证明结论:

在没有唯一键/主键重复时mysql replace into, into所做的事情就是新添加一个条目,条目各个属性的值与运行的语句内容有关。在有唯一键/主键重复时, into所做的事情就是

新条目各个属性的值只取决于运行的语句内容,与被删除的旧条目的值无关。

四、 into与on key 的区别

on key 更多内容参见《MySQL中ON KEY 的介绍与使用、批量更新、存在即更新不存在则插入 – 》

into与on key 在一定程度上都能实现无记录时插入,有记录时更新这个需求。但是强烈推荐使用on key 原因如下:

into在唯一索引冲突时,会删除原记录,然后新增一条记录,如果主键id是自增的会导致主键被改变; 而on key 在唯一索引冲突时是更新原记录,主键不变。 into唯一索引冲突时会导致主键自增值增加,但由于 事件记录为 会导致主从环境中表的 AUTO- 值不同,从库执行 事件并不会导致 AUTO- 值增加,所以从库表的 AUTO- 值会小于等于当前表的最新记录主键,当发生主从切换时向新的主库插入记录就会报 key 错误。

鉴于此MySQL中replace into详解、批量更新、不存在插入存在则更新、replace into的坑,很多使用 INTO 的场景,实际上需要的是 INTO … ON KEY (虽然也会增加自增值,但是不会出现从库表的 AUTO- 值会比当前表的最新记录主键小的情况),与 ‘ INTO …’ 不同,它只是更新重复行上的值,没有删除,也就不会导致原有主键值的变化。

1: into

2:on key

一,两者在数据库中无记录时都执行插入操作;在数据库中有记录时都执行“更新”操作。

二,二者在判断有无记录时,都是根据表里的主键或唯一索引。

三,检索到存在记录时,1是先删除原记录,再插入新记录;而2是保持原记录不变,更新指定的字段。

如表中有如下记录,其中id是自增主键,col1是唯一索引:

(id, col1, col2,col3)= (1, a,b,c)

执行

into (col1, col2) (a,d)

则表中数据变为

(id, col1, col2,col3)= (2, a,d,null)

原记录完全删除,id发生自增。

执行

into (col1) (a)

on key col2=d

则表中数据变位

(id, col1, col2,col3)= (1, a,d,c)

col3保持不变,id未自增,不过在插入下一条记录时,id会跳跃。

五、 into的坑 5.1、 into与自动更新时间的坑

into在有主键或唯一索引冲突时,会执行+操作,若字段设置了自动更新,需要手动设置时间或者字段设置默认时间,否则时间字段会插入为空

如下sql:

drop table if exists user_test;
create table user_test(
	id int primary key auto_increment comment '主键',
	name varchar(30)  not null comment '姓名',
	update_time timestamp on update CURRENT_TIMESTAMP comment '更新时间'
) comment '测试表';
insert into user_test(name,update_time) value ('zhangsan','2000-01-01 00:00:00');

此时执行 into

replace into user_test(id,name) value (1,'zhangsan');

上图可以看出执行 into之后,的字段被更新为空了。

解决方案

# 方案一:建表时设置字段有默认时间
create table user_test(
	id int primary key auto_increment comment '主键',
	name varchar(30)  not null comment '姓名',
	update_time timestamp default current_timestamp on update CURRENT_TIMESTAMP comment '更新时间'
) comment '测试表';
# 方案二:replace into时手动设置时间
replace into user_test values(1,'zhangsan',now());

5.2、 into用唯一索引更新时会导致自增值+1

见本文《3.1.3、有主键有唯一索引且唯一索引冲突(有坑)》

5.3、 into同时有主键或唯一索引冲突时可能会删除多条记录

注意:使用 into时只能用主键更新或者唯一键更新,二选其一。若同时都冲突了,可能会导致异常

见本文《3.1.4、有主键有唯一索引且与一条主键冲突与另一条唯一键冲突(有坑)》

公告:
1. 本站所有资源来源于用户上传和网络,如有侵权请联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系站长处理!
6. 本站不售卖代码,资源标价只是站长收集整理的辛苦费!如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。
7. 站长QQ号码 2205675299

资源库 - 资源分享下载网 » MySQL中replace into详解、批量更新、不存在插入存在则更新、replace into的坑

常见问题FAQ

关于资源售价和售后服务的说明?
本站所有资源的标价均为本站收集资源的辛苦费,不代表资源本身的价值。软件是高智慧高价值的商品,不可能是白菜价。本站资源标价只是赞助费用,收取的赞助费仅用来维持本站的日常运营!毕竟收集整理资料需要投入云计算资源和站长大量的精力。
代码有没有售后服务和技术支持?
由于代码的运行具有不可预见性,本站不保证代码完整可运行,不提供技术支持和售后服务。 本站原创代码都是站长自己开发的,可以有偿提供技术支持服务。 网站里标明【亲测】的代码都是站长亲测过的,其他的代码由于精力有限,没有一一测试,不能保证代码就一定能够使用,更没有技术支持服务,下载前请自行斟酌。
有没有搭建服务?
由于搭建服务比较费时费力,所以本站除了原创代码外均不提供搭建服务。本站分享代码纯属兴趣爱好,不以盈利为目的,请勿咨询有没有搭建服务,谢谢理解。
链接地址失效了怎么办?
请带上资源链接地址联系客服,工作时间内我们看到后将第一时间回复。
关于解压密码
本站资源一般都没有加密,如果发现需要解压密码的,那么就输入 hao.35dc.com 试试。

发表评论

资源库,由老程序员细心甄别、精心筛选,只为提供优质的源码资源

关于我们 联系我们