INSERT … ON DUPLICATE KEY UPDATE 总结
- 当主键或唯一键冲突时,执行更新操作,否则执行插入操作,auto_increment始终累加。
- 更新操作受多个唯一键影响,在MySQL5.6.6之后的SBR中被标记为不安全的
- UPDATE子句可使用VALUES(col_name)使用Insert语句中列的值
- DELAYED选项将被忽略
- MySQL5.6.6之前,对于表级锁存储引擎(MyISAM),该语句会锁定分区表中所有分区。MySQL5.6.6之后,只会锁定所更新的分区(InnoDB无影响)
- INSERT … SELECT ON DUPLICATE KEY UPDATE可能导致主从数据不一致,因此该语句在MySQL5.6.4之后的SBR中被标记为不安全的。
- 当没有主键或唯一键冲突时,与replace相同相当于普通的insert.
mysql> create table test(a int primary key auto_increment,b varchar(10),c varchar(10),d int);
Query OK, 0 rows affected (0.03 sec)
mysql> alter table test add unique index uq_b(b);
Query OK, 0 rows affected (0.05 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> insert into test (a,b,c,d) values(1,'1','1',1) on duplicate key update c='2', d=2;
Query OK, 1 row affected (0.02 sec)
mysql> select * from test;
+---+------+------+------+
| a | b | c | d |
+---+------+------+------+
| 1 | 1 | 2 | 1 |
+---+------+------+------+
1 row in set (0.01 sec)
mysql> insert into test (a,b,c,d) values(2,'1','1',1) on duplicate key update d=2;
Query OK, 2 rows affected (0.00 sec)
mysql> select * from test;
+---+------+------+------+
| a | b | c | d |
+---+------+------+------+
| 1 | 1 | 2 | 2 |
+---+------+------+------+
1 row in set (0.00 sec)
mysql> insert into test (a,b,c,d) values(null,'2','2',1) on duplicate key update d= values(a);
Query OK, 1 row affected (0.01 sec)
mysql> select * from test;
+---+------+------+------+
| a | b | c | d |
+---+------+------+------+
| 1 | 1 | 2 | 2 |
| 2 | 2 | 2 | 1 |
+---+------+------+------+
2 rows in set (0.01 sec)
mysql> insert into test (a,b,c,d) values(null,'2','2',1) on duplicate key update d= values(a);
Query OK, 2 rows affected (0.01 sec)
mysql> select * from test;
+---+------+------+------+
| a | b | c | d |
+---+------+------+------+
| 1 | 1 | 2 | 2 |
| 2 | 2 | 2 | 3 |
+---+------+------+------+
2 rows in set (0.00 sec)
mysql> insert into test (a,b,c,d) values(null,'2','2',1) on duplicate key update d= values(a);
Query OK, 2 rows affected (0.01 sec)
mysql> select * from test;
+---+------+------+------+
| a | b | c | d |
+---+------+------+------+
| 1 | 1 | 2 | 2 |
| 2 | 2 | 2 | 4 |
+---+------+------+------+
2 rows in set (0.00 sec)
mysql> insert into test (a,b,c,d) values(null,'3','3',3);
Query OK, 1 row affected (0.01 sec)
mysql> select * from test;
+---+------+------+------+
| a | b | c | d |
+---+------+------+------+
| 1 | 1 | 2 | 2 |
| 2 | 2 | 2 | 4 |
| 5 | 3 | 3 | 3 |
+---+------+------+------+
3 rows in set (0.01 sec)
REPLACE总结
- 当主键或唯一键冲突时,执行删除操作,然后执行插入操作,否则直接执行插入操作。
- 使用REPLACE时,必须同时拥有INSERT及DELETE权限
- MySQL 5.6.2之后,REPLACE可使用PARTITION选项指明明确的分区或子分区
- REPLACE不能使用冲突列的值,如不指定列值将被设置为默认值
- 删除操作受多个唯一键影响,受影响的行数是删除和插入的行的总和
- REPLACE表不支持子查询中查询同一个表
- REPLACE … SELECT可能导致主从数据不一致,因此该语句在MySQL5.6.4之后的SBR中被标记为不安全的。
- MySQL5.6.6之前,对于表级锁存储引擎(MyISAM),该语句会锁定分区表中所有分区,即使使用REPLACE … PARTITION语句。MySQL5.6.6之后,如不更新分区列,只锁定与WHERE子句匹配的分区,如更新分区列,整个表将被锁定
REPLACE算法(LOAD DATA… REPLACE):
- 尝试向表中插入新记录
- 因为主键或唯一索引中的重复键错误导致插入失败
- 从表中删除与重复键值冲突的记录
- 再次向表中插入新记录
mysql> select * from test;
+----+------+------+------+
| a | b | c | d |
+----+------+------+------+
| 1 | 1 | 2 | 2 |
| 2 | 2 | 2 | 2 |
| 4 | 4 | 4 | 4 |
| 5 | 3 | 3 | 7 |
| 8 | 12 | 8 | 8 |
| 13 | 14 | 10 | 14 |
| 14 | 10 | 10 | 10 |
+----+------+------+------+
7 rows in set (0.01 sec)
mysql> replace into test (a,b,c,d) values (14,'14',9,9);
Query OK, 3 rows affected (0.01 sec)
mysql> select * from test;
+----+------+------+------+
| a | b | c | d |
+----+------+------+------+
| 1 | 1 | 2 | 2 |
| 2 | 2 | 2 | 2 |
| 4 | 4 | 4 | 4 |
| 5 | 3 | 3 | 7 |
| 8 | 12 | 8 | 8 |
| 14 | 14 | 9 | 9 |
+----+------+------+------+
6 rows in set (0.00 sec)
mysql> replace into test (a,b,c,d) values (14,NULL,'',14);
Query OK, 2 rows affected (0.01 sec)
mysql> select * from test;
+----+------+------+------+
| a | b | c | d |
+----+------+------+------+
| 1 | 1 | 2 | 2 |
| 2 | 2 | 2 | 2 |
| 4 | 4 | 4 | 4 |
| 5 | 3 | 3 | 7 |
| 8 | 12 | 8 | 8 |
| 14 | NULL | | 14 |
+----+------+------+------+
6 rows in set (0.00 sec)
mysql> REPLACE INTO test SET a = 14 ,b= (select b from test where b = 12) ,c='12',d=12;
ERROR 1093 (HY000): You can't specify target table 'test' for update in FROM clause
mysql> select b from test where b = 12;
+------+
| b |
+------+
| 12 |
+------+
1 row in set (0.02 sec)
mysql> REPLACE INTO test SET a = 14 ,b= (select '12') ,c='12',d=12;
Query OK, 3 rows affected (0.01 sec)
mysql> select * from test;
+----+------+------+------+
| a | b | c | d |
+----+------+------+------+
| 1 | 1 | 2 | 2 |
| 2 | 2 | 2 | 2 |
| 4 | 4 | 4 | 4 |
| 5 | 3 | 3 | 7 |
| 14 | 12 | 12 | 12 |
+----+------+------+------+
5 rows in set (0.00 sec)