MySQL插入语句(四种)

总结

指令 已存在 不存在 举例
insert 报错 插入 insert into names(name, age) values(“小明”, 23);
insert ignore 忽略 插入 insert ignore into names(name, age) values(“小明”, 24);
replace 替换 插入 replace into names(name, age) values(“小明”, 25);
insert update 修改 插入 INSERT INTO USER VALUES(1,2) ON DUPLICATE KEY UPDATE NAME=2;
#直接插入,有则报错,没有就插入
#错误主键重复,错误代码: 1062 Duplicate entry '1' for key 'PRIMARY'
INSERT INTO same VALUES(1,2);
#直接插入,有则忽略,没有就插入
INSERT IGNORE INTO same VALUES(1,2);
#替换插入,有则替换,没有就插入(有则先删后插,外键级联时不可用)
REPLACE INTO same VALUES(1,2);
#替换插入,有则替换,没有就插入(有则修改,外键级联时可用)
INSERT INTO USER VALUES(1,2) ON DUPLICATE KEY UPDATE NAME=2;

#复制旧表插入新表,都可使用
INSERT INTO same3 SELECT * FROM same;
INSERT IGNORE INTO same3 SELECT * FROM same;
REPLACE INTO same3 SELECT * FROM same;

(1)通过主键判断是否重复

insert into 插入

insert ignore into 忽略重复插入

replace into 替换插入,重复先删后增

(2)replace into原理

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

(3)replace into的应用注意事项

1)插入数据的表必须有主键或者是唯一索引!否则的话,replace into 会直接插入数据,这将导致表中出现重复的数据。

2)如果数据库里边有这条记录,则直接修改这条记录;如果没有则,则直接插入,在有外键的情况下,对主表进行这样操作时,因为如果主表存在一条记录,被从表所用时,(如果此时不是级联删除的话)直接使用replace into是会报错的,这和replace into的内部原理是相关(ps.它会先删除然后再插入)。先删除该条存在的数据,然后再次插入这条数据,这和外键约束相悖呢。

(4)insert update的应用注意事项

1)向数据库插入记录时,有时会有这种需求,当符合某种条件的数据存在时,去修改它,不存在时,则新增,也就是saveOrUpdate操作。这时候就可以用到MySQL中的INSERT ... ON DUPLICATE KEY UPDATE语句。

该语句是基于唯一索引或主键使用。

INSERT INTO  same(a,c) VALUES (1,2) ON DUPLICATE KEY UPDATE c=c+1;
-- 当字段a为唯一索引或主键时,如果表中已经存在了a=1,下面语句会有相同的效果:
UPDATE  same SET c=c+1 WHERE a=1;

2)ON DUPLICATE KEY UPDATE后面可以放多个字段,用英文逗号分割。使用ON DUPLICATE KEY UPDATE,最终如果插入了一个新行,则受影响的行数是1,如果修改了已存在的一行数据,则受影响的行数是2。

3)通常的,在ON DUPLICATE KEY UPDATE语句中,我们应该避免多个唯一索引的情况。

-- a和b为唯一索引
INSERT INTO same (a,b,c) VALUES (1,2,3) ON DUPLICATE KEY UPDATE c=c+1;
-- 则该语句和下面的update语句是等效的:
UPDATE same SET c=c+1 WHERE a=1 OR b=2 LIMIT 1;

如果a=1 OR b=2匹配了多行,则只有一行会被修改。如果你的本意是想改掉a=1 and b=2的这一行,那将得到错误的结构。

(4)insert 的应用注意事项

注意:insert into select 可能造成锁表导致事故,阿里MySQL5.7以后不支持

为何会锁表,转载自:https://blog.csdn.net/qq_21383435/article/details/107475762 (CSDN-同事因误用insert被开除了)

文章核心内容提取:

在默认可重复读隔离级别下:insert into order_record select * from order_today 加锁规则是:order_record 表锁,order_today 逐步锁(扫描一个锁一个)。

分析执行过程:

在这里插入图片描述

通过观察迁移 SQL 的执行情况你会发现 order_today 是全表扫描,也就意味着在执行 insert into select from 语句时,MySQL 会从上到下扫描 order_today 内的记录并且加锁,这样一来不就和直接锁表是一样了。

解决方案

由于查询条件会导致 order_today 全表扫描,什么能避免全表扫描呢,很简单嘛,给 pay_success_time 字段添加一个 idx_pay_suc_time 索引就可以了。

由于走索引查询,就不会出现扫描全表的情况而锁表了,只会锁定符合条件的记录。

最终的 SQL:

INSERT INTO order_record SELECT
    * 
FROM
    order_today FORCE INDEX (idx_pay_suc_time)
WHERE
    pay_success_time <= '2020-03-08 00:00:00';

执行过程如下:

在这里插入图片描述