MySQL 常用插入语法总结

文章思维导图

MySQL 常用插入语句总结

当MySQL表字段设置unique key或者primary key时,被约束的字段就必须是唯一的。新插入数据直接使用insert into,如果出现唯一性冲突,就会抛出异常。我们应该根据需求选择合适的插入语句。

为了演示,我们先新建一张user表,SQL语句如下:

CREATE TABLE `user`  (
  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '无意义自增id',
  `username` varchar(64)  DEFAULT NULL COMMENT '用户名',
  `password` varchar(64)  DEFAULT NULL COMMENT '密码',
  `mobile_phone_number` varchar(20) DEFAULT NULL COMMENT '手机号码',
  `email` varchar(64)  DEFAULT NULL COMMENT '邮箱',
  `delete_state` tinyint(1) UNSIGNED DEFAULT 0 COMMENT '用户状态,1表示删除,0表示未删除',
  `create_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime(0) DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  UNIQUE INDEX `uk_username`(`username`)  COMMENT '用户名唯一'
) ENGINE = InnoDB;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user`(username,password,mobile_phone_number,email,delete_state,create_time,update_time) VALUES('JourWon', '123456', '13800000000', 'JourWon@163.com', 0, CURRENT_TIMESTAMP, NULL);
INSERT INTO `user`(username,password,mobile_phone_number,email,delete_state,create_time,update_time) VALUES('马云', '123456', '13800000011', 'JackMa@163.com', 0, CURRENT_TIMESTAMP, NULL);
INSERT INTO `user`(username,password,mobile_phone_number,email,delete_state,create_time,update_time) VALUES('马化腾', '123456', '13800000022', 'PonyMa@163.com', 0, CURRENT_TIMESTAMP, NULL);
INSERT INTO `user`(username,password,mobile_phone_number,email,delete_state,create_time,update_time) VALUES('李彦宏', '123456', '13800000033', 'RobinLee@163.com', 0, CURRENT_TIMESTAMP, NULL);
INSERT INTO `user`(username,password,mobile_phone_number,email,delete_state,create_time,update_time) VALUES('任正非', '123456', '13800000044', 'RenZhengfei@163.com', 0, CURRENT_TIMESTAMP, NULL);
INSERT INTO `user`(username,password,mobile_phone_number,email,delete_state,create_time,update_time) VALUES('Jobs', '123456', '13800000055', 'Jobs@163.com', 0, CURRENT_TIMESTAMP, NULL);
INSERT INTO `user`(username,password,mobile_phone_number,email,delete_state,create_time,update_time) VALUES('Bill Gates', '123456', '13800000066', 'Bill Gates@163.com', 0, CURRENT_TIMESTAMP, NULL);
INSERT INTO `user`(username,password,mobile_phone_number,email,delete_state,create_time,update_time) VALUES('Buffett', '123456', '13800000077', 'Buffett@163.com', 0, CURRENT_TIMESTAMP, NULL);
mysql> select * from user;
+----+------------+----------+---------------------+---------------------+--------------+---------------------+-------------+
| id | username   | password | mobile_phone_number | email               | delete_state | create_time         | update_time |
+----+------------+----------+---------------------+---------------------+--------------+---------------------+-------------+
|  1 | JourWon    | 123456   | 13800000000         | JourWon@163.com     |            0 | 2021-03-03 11:16:39 | NULL        |
|  2 | 马云       | 123456   | 13800000011         | JackMa@163.com      |            0 | 2021-03-03 11:16:39 | NULL        |
|  3 | 马化腾     | 123456   | 13800000022         | PonyMa@163.com      |            0 | 2021-03-03 11:16:39 | NULL        |
|  4 | 李彦宏     | 123456   | 13800000033         | RobinLee@163.com    |            0 | 2021-03-03 11:16:39 | NULL        |
|  5 | 任正非     | 123456   | 13800000044         | RenZhengfei@163.com |            0 | 2021-03-03 11:16:39 | NULL        |
|  6 | Jobs       | 123456   | 13800000055         | Jobs@163.com        |            0 | 2021-03-03 11:16:39 | NULL        |
|  7 | Bill Gates | 123456   | 13800000066         | Bill Gates@163.com  |            0 | 2021-03-03 11:16:39 | NULL        |
|  8 | Buffett    | 123456   | 13800000077         | Buffett@163.com     |            0 | 2021-03-03 11:16:40 | NULL        |
+----+------------+----------+---------------------+---------------------+--------------+---------------------+-------------+
8 rows in set (0.00 sec)

常用插入语句

insert into

当插入数据时,如果唯一性校验出现重复问题,则报错;

如果没有重复性问题,则执行插入操作。

简单总结:重复则直接报错,sql 语句不执行,不重复则插入。

示例

INSERT INTO `user`(username,password,mobile_phone_number,email,delete_state,create_time,update_time) VALUES('Buffett', '123456', '13800000077', 'Buffett@163.com', 0, CURRENT_TIMESTAMP, NULL);

执行结果

mysql> INSERT INTO `user`(username,password,mobile_phone_number,email,delete_state,create_time,update_time) VALUES('Buffett', '123456', '13800000077', 'Buffett@163.com', 0, CURRENT_TIMESTAMP, NULL);
ERROR 1062 (23000): Duplicate entry 'Buffett' for key 'uk_username'

insert ignore into

当插入数据时,如果唯一性校验出现重复问题,则忽略错误,只以警告形式返回,不执行此SQL语句;

如果没有重复性问题,则执行插入操作。

简单总结:重复则忽略,sql 语句不执行,不重复则插入。

示例

insert ignore into `user`(username,password,mobile_phone_number,email,delete_state,create_time,update_time) VALUES('Buffett', '123456', '13800000077', 'Buffett@163.com', 0, CURRENT_TIMESTAMP, NULL);

执行结果

mysql> insert ignore into `user`(username,password,mobile_phone_number,email,delete_state,create_time,update_time) VALUES('Buffett', '123456', '13800000077', 'Buffett@163.com', 0, CURRENT_TIMESTAMP, NULL);
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> show warnings;
+---------+------+-------------------------------------------------+
| Level   | Code | Message                                         |
+---------+------+-------------------------------------------------+
| Warning | 1062 | Duplicate entry 'Buffett' for key 'uk_username' |
+---------+------+-------------------------------------------------+
1 row in set (0.00 sec)

mysql> select * from user where username='Buffett';
+----+----------+----------+---------------------+-----------------+--------------+---------------------+-------------+
| id | username | password | mobile_phone_number | email           | delete_state | create_time         | update_time |
+----+----------+----------+---------------------+-----------------+--------------+---------------------+-------------+
|  8 | Buffett  | 123456   | 13800000077         | Buffett@163.com |            0 | 2021-03-03 11:16:40 | NULL        |
+----+----------+----------+---------------------+-----------------+--------------+---------------------+-------------+
1 row in set (0.00 sec)

insert into ... on duplicate key update

当插入数据时,如果唯一性校验出现重复问题,则在原有记录基础上,更新指定字段内容,其它字段内容保留;

如果没有重复性问题,则执行插入操作。

简单总结:重复则更新指定字段,不重复则插入。

示例

INSERT INTO `user` ( username, PASSWORD, mobile_phone_number, email ) VALUES('Buffett', '123456', '13800000088', 'Buffett@163.com' ) ON DUPLICATE KEY UPDATE mobile_phone_number = '13800000088';

执行结果

mysql> INSERT INTO `user` ( username, PASSWORD, mobile_phone_number, email ) VALUES('Buffett', '123456', '13800000088', 'Buffett@163.com' ) ON DUPLICATE KEY UPDATE mobile_phone_number = '13800000088';
Query OK, 2 rows affected (0.00 sec)

表记录,mobile_phone_number 从 '13800000077' 更新为 '13800000088' 了,update_time也从NULL更新为有值了,但是id没有变:

mysql>  select * from user where username='Buffett';
+----+----------+----------+---------------------+-----------------+--------------+---------------------+---------------------+
| id | username | password | mobile_phone_number | email           | delete_state | create_time         | update_time         |
+----+----------+----------+---------------------+-----------------+--------------+---------------------+---------------------+
|  8 | Buffett  | 123456   | 13800000088         | Buffett@163.com |            0 | 2021-03-03 11:16:40 | 2021-03-03 11:19:30 |
+----+----------+----------+---------------------+-----------------+--------------+---------------------+---------------------+
1 row in set (0.00 sec)

replace into

replace into表示插入替换数据,当插入数据时,如果唯一性校验出现重复问题,删除旧记录,插入新记录;

如果没有重复性问题,则执行插入操作,效果和insert into是一样的。

简单总结:重复则先删除再插入新记录,不重复则插入

示例

replace into  `user` (username, password, mobile_phone_number, email ) values('Buffett', '123456', '13800000099', 'Buffett@163.com');

执行结果

mysql> replace into  `user` (username, password, mobile_phone_number, email ) values('Buffett', '123456', '13800000099', 'Buffett@163.com');
Query OK, 2 rows affected (0.00 sec)

表记录,idmobile_phone_number变了,update_time变为了字段默认值NULL:

mysql> select * from user where username='Buffett';
+----+----------+----------+---------------------+-----------------+--------------+---------------------+-------------+
| id | username | password | mobile_phone_number | email           | delete_state | create_time         | update_time |
+----+----------+----------+---------------------+-----------------+--------------+---------------------+-------------+
| 12 | Buffett  | 123456   | 13800000099         | Buffett@163.com |            0 | 2021-03-03 14:40:31 | NULL        |
+----+----------+----------+---------------------+-----------------+--------------+---------------------+-------------+
1 row in set (0.00 sec)

replace into 的“坑”

replace into 执行的逻辑:

  1. 遇到PRIMARY KEYUNIQUE索引的,新记录与旧记录有冲突的(这里实际产生了异常duplicate key error),replace into会把旧记录删除,然后再插入新记录, insert into ... on deplicate key update则只会更新。
  2. 若是新记录没有冲突,就直接插入一条新记录,与insert into一样。

示例一

INSERT INTO `user` (username, PASSWORD, mobile_phone_number, email ) VALUES('Buffett', '123456', '13800000088', 'Buffett@163.com' ) ON DUPLICATE KEY UPDATE mobile_phone_number = '13800000088';

示例一insert into ... on deplicate key update操作在binlog中记录为:

### UPDATE `zlz`.`user`
### WHERE
###   @1=8 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2='Buffett' /* VARSTRING(192) meta=192 nullable=1 is_null=0 */
###   @3='123456' /* VARSTRING(192) meta=192 nullable=1 is_null=0 */
###   @4='13800000077' /* VARSTRING(60) meta=60 nullable=1 is_null=0 */
###   @5='Buffett@163.com' /* VARSTRING(192) meta=192 nullable=1 is_null=0 */
###   @6=0 /* TINYINT meta=0 nullable=1 is_null=0 */
###   @7='2021-03-03 11:25:22' /* DATETIME(0) meta=0 nullable=0 is_null=0 */
###   @8=NULL /* DATETIME(0) meta=0 nullable=1 is_null=1 */
### SET
###   @1=8 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2='Buffett' /* VARSTRING(192) meta=192 nullable=1 is_null=0 */
###   @3='123456' /* VARSTRING(192) meta=192 nullable=1 is_null=0 */
###   @4='13800000088' /* VARSTRING(60) meta=60 nullable=1 is_null=0 */
###   @5='Buffett@163.com' /* VARSTRING(192) meta=192 nullable=1 is_null=0 */
###   @6=0 /* TINYINT meta=0 nullable=1 is_null=0 */
###   @7='2021-03-03 11:16:40' /* DATETIME(0) meta=0 nullable=0 is_null=0 */
###   @8='2021-03-03 11:19:30' /* DATETIME(0) meta=0 nullable=1 is_null=0 */

示例二

replace into  `user` ( username, password, mobile_phone_number, email ) values('Buffett', '123456', '13800000099', 'Buffett@163.com' );

示例二replace into 操作在binlog中记录为:

### UPDATE `zlz`.`user`
### WHERE
###   @1=8 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2='Buffett' /* VARSTRING(192) meta=192 nullable=1 is_null=0 */
###   @3='123456' /* VARSTRING(192) meta=192 nullable=1 is_null=0 */
###   @4='13800000088' /* VARSTRING(60) meta=60 nullable=1 is_null=0 */
###   @5='Buffett@163.com' /* VARSTRING(192) meta=192 nullable=1 is_null=0 */
###   @6=0 /* TINYINT meta=0 nullable=1 is_null=0 */
###   @7='2021-03-03 11:16:40' /* DATETIME(0) meta=0 nullable=0 is_null=0 */
###   @8='2021-03-03 11:19:30' /* DATETIME(0) meta=0 nullable=1 is_null=0 */
### SET
###   @1=12 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2='Buffett' /* VARSTRING(192) meta=192 nullable=1 is_null=0 */
###   @3='123456' /* VARSTRING(192) meta=192 nullable=1 is_null=0 */
###   @4='13800000099' /* VARSTRING(60) meta=60 nullable=1 is_null=0 */
###   @5='Buffett@163.com' /* VARSTRING(192) meta=192 nullable=1 is_null=0 */
###   @6=0 /* TINYINT meta=0 nullable=1 is_null=0 */
###   @7='2021-03-03 14:40:31' /* DATETIME(0) meta=0 nullable=0 is_null=0 */
###   @8=NULL /* DATETIME(0) meta=0 nullable=1 is_null=1 */

从示例可以看出,使用replace into 会有以下问题:

  1. 把旧记录删除是删除的整行记录,之后,插入的新记录只是插入了那些指定的字段,原本不想更新的字段,此时直接为默认值了,会导致数据丢失;
  2. 自增主键id会更新。若旧记录的id跟其他表是有关联的,更新后新记录会产生新的id,导致这种关联丢失;
  3. 当执行 replace into 时,如果遇到 unique key 冲突,mysql执行的是delete+insert两步操作,但是binlog只会保存一条update语句,造成主库中 AUTO_INCREAMENT 进行+1操作。从库不执行该操作,造成mysql主从的 AUTO_INCREMEN 不一致,
    mysql主从切换后,从库变为主库,其中新主库(原从库) AUTO_INCREMENT 较为落后,导致新插入的数据主键可能已经存在数据表中,新插入数据会出现异常,直到AUTO_INCREMENT增加到原来主机器的值为止。

REPLACE is a MySQL extension to the SQL standard. It either inserts, or deletes and inserts. For another MySQL extension to standard SQL—that either inserts or updates—see Section 13.2.5.2, “INSERT ... ON DUPLICATE KEY UPDATE Statement”.

如何避“坑”

  1. INSERT INTO … ON DUPLICATE KEY UPDATE代替 REPLACE INTO。 很多使用 REPLACE INTO 的场景,实际上需要的可能是 INSERT INTO … ON DUPLICATE KEY UPDATE,在正确理解 REPLACE INTO 行为和副作用的前提下,谨慎使用 REPLACE INTO
  2. 使用REPLACE INTO 时指定表中所有列的值(包括主键)或 MySQL8.0 版本。
    示例
replace into  `user`(id,username, password, mobile_phone_number, email,delete_state,create_time,update_time) values(8,'Buffett', '123456', '13800000077', 'Buffett@163.com',0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);

执行结果

mysql> replace into  `user`(id,username, password, mobile_phone_number, email,delete_state,create_time,update_time) values(8,'Buffett', '123456', '13800000077', 'Buffett@163.com',0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);
Query OK, 2 rows affected (0.00 sec)

因为全部列都是指定的值,所以,相当于所有字段全部更新了一次。

mysql> select * from user where username='Buffett';
+----+----------+----------+---------------------+-----------------+--------------+---------------------+---------------------+
| id | username | password | mobile_phone_number | email           | delete_state | create_time         | update_time         |
+----+----------+----------+---------------------+-----------------+--------------+---------------------+---------------------+
|  8 | Buffett  | 123456   | 13800000077         | Buffett@163.com |            0 | 2021-03-03 15:24:49 | 2021-03-03 15:24:49 |
+----+----------+----------+---------------------+-----------------+--------------+---------------------+---------------------+
1 row in set (0.00 sec)

binlog中的记录:

### UPDATE `zlz`.`user`
### WHERE
###   @1=14 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2='Buffett' /* VARSTRING(192) meta=192 nullable=1 is_null=0 */
###   @3='123456' /* VARSTRING(192) meta=192 nullable=1 is_null=0 */
###   @4='13800000099' /* VARSTRING(60) meta=60 nullable=1 is_null=0 */
###   @5='Buffett@163.com' /* VARSTRING(192) meta=192 nullable=1 is_null=0 */
###   @6=0 /* TINYINT meta=0 nullable=1 is_null=0 */
###   @7='2021-03-03 15:17:13' /* DATETIME(0) meta=0 nullable=0 is_null=0 */
###   @8=NULL /* DATETIME(0) meta=0 nullable=1 is_null=1 */
### SET
###   @1=8 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2='Buffett' /* VARSTRING(192) meta=192 nullable=1 is_null=0 */
###   @3='123456' /* VARSTRING(192) meta=192 nullable=1 is_null=0 */
###   @4='13800000077' /* VARSTRING(60) meta=60 nullable=1 is_null=0 */
###   @5='Buffett@163.com' /* VARSTRING(192) meta=192 nullable=1 is_null=0 */
###   @6=0 /* TINYINT meta=0 nullable=1 is_null=0 */
###   @7='2021-03-03 15:24:49' /* DATETIME(0) meta=0 nullable=0 is_null=0 */
###   @8='2021-03-03 15:24:49' /* DATETIME(0) meta=0 nullable=1 is_null=0 */

使用场景总结

如果出现重复异常,希望捕获异常,则使用insert into;

如果出现重复异常,希望保存旧纪录,忽略新纪录,则使用insert ignore into;

如果出现重复异常,希望更新指定字段,则使用insert into … on duplicate key update;

如果出现重复异常,希望删除旧记录,插入新记录,则使用replace into

参考文档

https://blog.csdn.net/ThinkWon/article/details/106610789

https://dsb123dsb.github.io/2019/01/13/%E4%B8%80%E6%AE%B5replace-into-%E5%BC%95%E5%8F%91%E7%9A%84%E8%A1%80%E6%A1%88/

https://blog.csdn.net/quuqu/article/details/110636263

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345

推荐阅读更多精彩内容