Mysql学习二 INSERT、INSERT IGNORE和REPLACE

先准备测试表和几条测试数据

CREATE TABLE IF NOT EXISTS `employees_example` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `first_name` varchar(30) NOT NULL DEFAULT "",
  `last_name` varchar(40) NOT NULL DEFAULT "",
  `position` varchar(25) NOT NULL DEFAULT "",
  `home_address` varchar(50) NOT NULL DEFAULT "",
  `home_phone` varchar(12) NOT NULL DEFAULT "",
  `employee_code` varchar(25) NOT NULL DEFAULT "",
  PRIMARY KEY (`id`),
  UNIQUE KEY `employee_code` (`employee_code`),
  KEY `phone` (home_phone),
  KEY `full_name` (`first_name`,`last_name`)
) ;

INSERT INTO `employees_example` (`first_name`, `last_name`, `position`, `home_address`, `home_phone`, `employee_code`)
  VALUES
  ('Mustapha', 'Mond', 'Chief Executive Officer', '692 Promiscuous Plaza', '326-555-3492', 'MM1'),
  ('Henry', 'Foster', 'Store Manager', '314 Savage Circle', '326-555-3847', 'HF1'),
  ('Bernard', 'Marx', 'Cashier', '1240 Ambient Avenue', '326-555-8456', 'BM1');

INSERT

#插入主键相同的数据
mysql> INSERT INTO `employees_example` (`id`,`first_name`, `last_name`, `position`, `home_address`, `home_phone`, `employee_code`)
VALUES (3,'Bernard', 'Marx', 'Cashier', '1240 Ambient Avenue', '326-555-8456', 'BM1');
1062 - Duplicate entry '3' for key 'PRIMARY'
#插入唯一索引相同的数据
mysql> INSERT INTO `employees_example` (`first_name`, `last_name`, `position`, `home_address`, `home_phone`, `employee_code`)
VALUES ('Bernard', 'Marx', 'Cashier', '1240 Ambient Avenue', '326-555-8456', 'BM1');
1062 - Duplicate entry 'BM1' for key 'employee_code'

可以看到,插入主键或唯一索引相同的数据会出现错误。

INSERT IGNORE

我们先看下现有的数据

mysql> select * from employees_example;
+----+------------+-----------+-------------------------+-----------------------+--------------+---------------+
| id | first_name | last_name | position                | home_address          | home_phone   | employee_code |
+----+------------+-----------+-------------------------+-----------------------+--------------+---------------+
|  1 | Mustapha   | Mond      | Chief Executive Officer | 692 Promiscuous Plaza | 326-555-3492 | MM1           |
|  2 | Henry      | Foster    | Store Manager           | 314 Savage Circle     | 326-555-3847 | HF1           |
|  3 | Bernard    | Marx      | Cashier                 | 1240 Ambient Avenue   | 326-555-8456 | BM1           |
+----+------------+-----------+-------------------------+-----------------------+--------------+---------------+
3 rows in set

执行之前的插入语句,将insert替换成insert ignore。

mysql> INSERT IGNORE `employees_example` (`id`,`first_name`, `last_name`, `position`, `home_address`, `home_phone`, `employee_code`)
VALUES (3,'Bernard', 'Marx', 'Cashier', '1240 Ambient Avenue', '326-555-8456', 'BM1');
Query OK, 0 rows affected

mysql> INSERT IGNORE `employees_example` (`first_name`, `last_name`, `position`, `home_address`, `home_phone`, `employee_code`)
VALUES ('Bernard', 'Marx', 'Cashier', '1240 Ambient Avenue', '326-555-8456', 'BM1');
Query OK, 0 rows affected

查询表中数据,数据没有新增,但是不会报错。

但是我们再插入一条与主键和唯一索引不冲突的数据,然后查看表中数据。

mysql> INSERT IGNORE `employees_example` (`first_name`, `last_name`, `position`, `home_address`, `home_phone`, `employee_code`) VALUES ('Lenina', 'Crowne', 'Cashier', '281 Bumblepuppy Boulevard', '328-555-2349', 'LC1');
Query OK, 1 row affected

mysql> select * from employees_example;
+----+------------+-----------+-------------------------+---------------------------+--------------+---------------+
| id | first_name | last_name | position                | home_address              | home_phone   | employee_code |
+----+------------+-----------+-------------------------+---------------------------+--------------+---------------+
|  1 | Mustapha   | Mond      | Chief Executive Officer | 692 Promiscuous Plaza     | 326-555-3492 | MM1           |
|  2 | Henry      | Foster    | Store Manager           | 314 Savage Circle         | 326-555-3847 | HF1           |
|  3 | Bernard    | Marx      | Cashier                 | 1240 Ambient Avenue       | 326-555-8456 | BM1           |
|  5 | Lenina     | Crowne    | Cashier                 | 281 Bumblepuppy Boulevard | 328-555-2349 | LC1           |
+----+------------+-----------+-------------------------+---------------------------+--------------+---------------+
4 rows in set

发现表中的自增主键:id 不连续了。

如果表中有自增主键,INSERT IGNORE 插入无主键且唯一索引冲突的数据,会使AUTO_INCREMENT发生变化。

REPLACE INTO

replace into的三种形式

1replace into tbl_name(col_name, ...) values(...)
2replace into tbl_name(col_name, ...) select ...
3replace into tbl_name set col_name = value, ...

我们先试着执行一下几条sql

#替换唯一索引冲突的数据
mysql> REPLACE INTO `employees_example` (`first_name`, `last_name`, `employee_code`) VALUES ('Lenina', 'Crowne', 'LC1');
Query OK, 2 rows affected

mysql> SELECT * FROM employees_example;
+----+------------+-----------+-------------------------+-----------------------+--------------+---------------+
| id | first_name | last_name | position                | home_address          | home_phone   | employee_code |
+----+------------+-----------+-------------------------+-----------------------+--------------+---------------+
|  1 | Mustapha   | Mond      | Chief Executive Officer | 692 Promiscuous Plaza | 326-555-3492 | MM1           |
|  2 | Henry      | Foster    | Store Manager           | 314 Savage Circle     | 326-555-3847 | HF1           |
|  3 | Bernard    | Marx      | Cashier                 | 1240 Ambient Avenue   | 326-555-8456 | BM1           |
|  6 | Lenina     | Crowne    |                         |                       |              | LC1           |
+----+------------+-----------+-------------------------+-----------------------+--------------+---------------+
4 rows in set

#替换主键冲突的数据
mysql>REPLACE INTO `employees_example` (`id`,`first_name`, `last_name`) VALUES (6,'Lenina', 'Crowne');
Query OK, 2 rows affected

mysql> SELECT * FROM employees_example;
+----+------------+-----------+-------------------------+-----------------------+--------------+---------------+
| id | first_name | last_name | position                | home_address          | home_phone   | employee_code |
+----+------------+-----------+-------------------------+-----------------------+--------------+---------------+
|  1 | Mustapha   | Mond      | Chief Executive Officer | 692 Promiscuous Plaza | 326-555-3492 | MM1           |
|  2 | Henry      | Foster    | Store Manager           | 314 Savage Circle     | 326-555-3847 | HF1           |
|  3 | Bernard    | Marx      | Cashier                 | 1240 Ambient Avenue   | 326-555-8456 | BM1           |
|  6 | Lenina     | Crowne    |                         |                       |              |               |
+----+------------+-----------+-------------------------+-----------------------+--------------+---------------+
4 rows in set

#替换唯一索引和主键均冲突的数据
mysql> REPLACE INTO `employees_example` (`id`,`first_name`, `last_name`, `employee_code`) VALUES (6,'Henry', 'Foster', 'HF1');
Query OK, 3 rows affected

mysql> SELECT * FROM employees_example;
+----+------------+-----------+-------------------------+-----------------------+--------------+---------------+
| id | first_name | last_name | position                | home_address          | home_phone   | employee_code |
+----+------------+-----------+-------------------------+-----------------------+--------------+---------------+
|  1 | Mustapha   | Mond      | Chief Executive Officer | 692 Promiscuous Plaza | 326-555-3492 | MM1           |
|  3 | Bernard    | Marx      | Cashier                 | 1240 Ambient Avenue   | 326-555-8456 | BM1           |
|  6 | Henry      | Foster    |                         |                       |              | HF1           |
+----+------------+-----------+-------------------------+-----------------------+--------------+---------------+
3 rows in set

可以根据结果看到,REPLACE INTO会删除掉主键或唯一索引发生重复的行,然后再插入新的数据。

The REPLACE statement returns a count to indicate the number of rows affected. This is the sum of the rows deleted and inserted. If the count is 1 for a single-row REPLACE, a row was inserted and no rows were deleted. If the count is greater than 1, one or more old rows were deleted before the new row was inserted. It is possible for a single row to replace more than one old row if the table contains multiple unique indexes and the new row duplicates values for different old rows in different unique indexes.

REPLACE语句返回受影响的行数的值,这个值是删除和插入的行的总和。如果单行的计数为1, REPLACE则插入一行并且不删除任何行。如果计数大于1,则在插入新行之前删除一个或多个旧行。如果表包含多个唯一索引,并且新行为不同唯一索引中的不同旧行重复值,则单行可以替换多个旧行。

 Values for all columns are taken from the values specified in the REPLACE statement. Any missing columns are set to their default values, just as happens for INSERT. You cannot refer to values from the current row and use them in the new row. If you use an assignment such as SET col_name = col_name + 1, the reference to the column name on the right hand side is treated as DEFAULT(col_name), so the assignment is equivalent to SET col_name = DEFAULT(col_name) + 1.
 To use REPLACE, you must have both the INSERT and DELETE privileges for the table.

所有REPLACE语句中列的值都应该被指定。任何缺少的列值都被设置为默认值,就像INSERT一样。并且不能从当前行引用值并在新行中使用它们。如果使用SET col_name = col_name + 1这样的赋值,那么对右边列名的引用将被视为默认值,因此赋值相当于SET col_name = DEFAULT(col_name) + 1。
要使用REPLACE,必须同时具有表的插入和删除特权。

REPLACE INTO在数据库主从切换后,可能会出现一些问题,具体可以参考MySQL Replace Into & Replication

INSERT INTO … ON DUPLICATE KEY UPDATE

mysql> INSERT INTO `test`.`employees_example` (`first_name`, `employee_code`) VALUES ('Helmholtz', 'HF1') ON DUPLICATE KEY UPDATE first_name = 'Helmholtz';
Query OK, 2 rows affected

这种方法也能实现REPLACE INTO的功能,且可以引用当前行的值。

mysql>INSERT INTO `test`.`employees_example` (`first_name`, `employee_code`) VALUES ('Mustapha', 'MM1') ON DUPLICATE KEY UPDATE first_name = CONCAT(first_name,' ','test');
Query OK, 2 rows affected

mysql> select * from employees_example limit 1;
+----+---------------+-----------+-------------------------+-----------------------+--------------+---------------+
| id | first_name    | last_name | position                | home_address          | home_phone   | employee_code |
+----+---------------+-----------+-------------------------+-----------------------+--------------+---------------+
|  1 | Mustapha test | Mond      | Chief Executive Officer | 692 Promiscuous Plaza | 326-555-3492 | MM1           |
+----+---------------+-----------+-------------------------+-----------------------+--------------+---------------+
1 row in set

如果表中有多个唯一索引,如employees_example表中的id和employee_code,INSERT INTO … ON DUPLICATE KEY UPDATE只会更新其中的一行。

With ON DUPLICATE KEY UPDATE, the affected-rows value per row is 1 if the row is inserted as a new row, 2 if an existing row is updated, and 0 if an existing row is set to its current values.

对于ON DUPLICATE KEY UPDATE,如果将行作为新行插入,则每行的受影响行值为1;如果更新现有行,则为2,如果现有行设置为其当前值,则为0。

但是发现使用INSERT INTO … ON DUPLICATE KEY UPDATE也会使表中的AUTO_INCREMENT也会增加。

可能发生问题:INSERT IGNORE,REPLACE INTO,INSERT INTO … ON DUPLICATE KEY UPDATE都会使表的AUTO_INCREMENT发生变化,是不是都会出现主从数据库AUTO_INCREMENT不一致的问题???

参考
REPLACE Syntax
INSERT … ON DUPLICATE KEY UPDATE Syntax

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值