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';
执行过程如下: