阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

MySQL replace into的使用细则

113次阅读
没有评论

共计 4436 个字符,预计需要花费 12 分钟才能阅读完成。

在 Oracle 中有 merge into 的语法,可以达到一个语句完成同时修改,添加数据的功能,MySQL 里面没有 merge into 的语法,却有 replace into。
我们来看看 replace into 的使用细则。
为了方便演示,我首先创建一个表 users
create table users(
user_id int(11) unsigned not null,
user_name varchar(64) default null,
primary key(user_id)
)engine=innodb default charset=UTF8;
插入 2 行数据,可能搞 Oracle 的同学就不适应了,SQL 怎么能这么写,不过用起来确实蛮有意思。
> insert into users (user_id,user_name) values(1,’aa’),(2,’bb’);
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0
数据情况如下:
> select * from users;
+———+———–+
| user_id | user_name |
+———+———–+
|      1 | aa        |
|      2 | bb        |
+———+———–+
2 rows in set (0.00 sec)
好了,我们来看看 replace into 的使用,如果向表里插入数据,表里已经存在同样的数据,replace into 是会直接更新还是会删除,然后插入。
要搞明白这一点很重要,因为这个直接会影响到数据的准确性。
我们先看看 replace into 的使用。比如插入下面的一条记录。
> replace into users(user_id, user_name) values(1, ‘cc’);
Query OK, 2 rows affected (0.00 sec)
完成之后数据的情况如下:
> select * from users;
+———+———–+
| user_id | user_name |
+———+———–+
|      1 | cc        |
|      2 | bb        |
+———+———–+
2 rows in set (0.00 sec)
看来数据像是被替换了,又好像是删除后,重新覆盖的。怎么验证呢。
我们可以先试试 trace 的方法。是否能够有所收获。
首先用 explain extended 的方式,这种方式会得到很多执行计划的细节信息。
MySQL replace into 的使用细则
根据输出来看,这种方式得不到预期的数据结果。
我们换一个方式,在 5.6 以上版本使用 optimizer_trace
> set optimizer_trace=”enabled=on”;
Query OK, 0 rows affected (0.00 sec)

> replace into users(user_id, user_name) values(1, ‘dd’);
Query OK, 2 rows affected (0.01 sec)
输出结果如下,还是没有得到很详细的信息。
MySQL replace into 的使用细则
这个时候不要气馁,要知道办法总比困难多。我们可以换一个新的思路来测试,而且还能顺带验证,何乐而不为。
我们重新创建一个表 users2, 和 users 的唯一不同在于 user_id 使用了 auto_increment 的方式。
CREATE TABLE `users2` (
user_id int(11) unsigned not null AUTO_INCREMENT,
user_name varchar(64) default null,
primary key(user_id)
)engine=innodb default charset=UTF8;

插入 3 行数据。
> INSERT INTO users2 (user_id,user_name) VALUES (1, ‘aa’), (2, ‘bb’), (3, ‘cc’);
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0
这个时候查看建表的 DDL 如下:
> SHOW CREATE TABLE users2\G
*************************** 1. row ***************************
      Table: users2
Create Table: CREATE TABLE `users2` (
  `user_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `user_name` varchar(64) DEFAULT NULL,
  PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8
1 row in set (0.01 sec)
数据情况如下:
> SELECT * FROM users2 ;
+———+———–+
| user_id | user_name |
+———+———–+
|      1 | aa        |
|      2 | bb        |
|      3 | cc        |
+———+———–+
3 rows in set (0.00 sec)
我们先做一个 replace into 的操作。
> REPLACE INTO users2 (user_id,user_name) VALUES (1, ‘dd’);
Query OK, 2 rows affected (0.00 sec)

数据情况如下,原来 user_id 为 1 的数据做了变更。
> SELECT * FROM users2;
+———+———–+
| user_id | user_name |
+———+———–+
|      1 | dd        |
|      2 | bb        |
|      3 | cc        |
+———+———–+
3 rows in set (0.01 sec)
再次查看 auto_increment 的值还是 4
> SHOW CREATE TABLE users2\G
*************************** 1. row ***************************
      Table: users2
Create Table: CREATE TABLE `users2` (
  `user_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `user_name` varchar(64) DEFAULT NULL,
  PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
这个时候还是很难得出一个结论,切记不要想当然。replace into 需要表中存在主键或者唯一性索引,user_id 存在主键,我们给 user_name 创建一个唯一性索引。
> alter table users2 add unique key users2_uq_name(user_name);
Query OK, 0 rows affected (0.06 sec)
Records: 0  Duplicates: 0  Warnings: 0
好了,重要的时刻到了,我们看看下面的语句的效果。只在语句中提及 user_name, 看看 user_id 是递增还是保留当前的值。
> REPLACE INTO users2 (user_name) VALUES (‘dd’);
Query OK, 2 rows affected (0.00 sec)
可以看到 user_id 做了递增,也就意味着这是一个全新的 insert 插入数据。
> select * from users2;
+———+———–+
| user_id | user_name |
+———+———–+
|      2 | bb        |
|      3 | cc        |
|      4 | dd        |
+———+———–+
3 rows in set (0.00 sec)
这个时候再次查看建表的 DDL 如下,auto_increment 确实是递增了。
CREATE TABLE `users2` (
  `user_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `user_name` varchar(64) DEFAULT NULL,
  PRIMARY KEY (`user_id`),
  UNIQUE KEY `users2_uq_name` (`user_name`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8
所以通过上面的测试和推理我们知道,replace into 是 delete,insert 的操作,而非基于当前数据的 update。
如此一来我们使用 replace into 的时候就需要格外注意,可能有些操作非我们所愿,如果插入数据时存在重复的数据,是更新当前记录的情况,该怎么办呢,可以使用 replace into 的姊妹篇语句,insert into on duplicate key 的方式,后面需要使用 update 选项。
比如我们还是基于上面的数据,插入 user_name 为 ’dd’ 的数据,如果存在则修改。
> INSERT INTO users2 (user_name) VALUES (‘dd’) ON DUPLICATE KEY UPDATE user_name=VALUES(user_name);
Query OK, 0 rows affected (0.00 sec)
根据运行结果来看,没有修改数据,比我们期望的还要好一些。
所以任何语句和功能都不是万能的,还得看场景,脱离了使用场景就很难说得清了。
此外,补充 replace into 的另外一种使用方式,供参考。
> replace into users2(user_id,user_name) select 2,’bbbb’  ;
Query OK, 2 rows affected (0.01 sec)
Records: 1  Duplicates: 1  Warnings: 0

> select *from users2;
+———+———–+
| user_id | user_name |
+———+———–+
|      2 | bbbb      |
|      3 | cc        |
|      4 | dd        |
+———+———–+
3 rows in set (0.00 sec)
其实再次查看 replace into 的使用,发现日志中已经赫然提醒,2 rows affected. 当然我们有过程有结论,也算是一种不错的尝试了。

本文永久更新链接地址 :http://www.linuxidc.com/Linux/2016-10/136032.htm

正文完
星哥说事-微信公众号
post-qrcode
 
星锅
版权声明:本站原创文章,由 星锅 2022-01-22发表,共计4436字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中