# 9.1 INSERT 语句

在本教程中，您将学习如何使用MySQL `INSERT`语句将数据插入到数据库表中。

## 1. 简单的MySQL INSERT语句

MySQL `INSERT`语句允许您将一行或多行插入到表中。下面说明了`INSERT`语句的语法：

```sql
INSERT INTO table(column1,column2...)
VALUES (value1,value2,...);
```

**首先**，在`INSERT INTO`子句之后，在括号内指定表名和逗号分隔列的列表。 **然后**，将括号内的相应列的逗号分隔值放在`VALUES`关键字之后。

在执行插入语句前，需要具有执行`INSERT`语句的`INSERT`权限。 让我们创建一个名为`tasks`的新表来练习`INSERT`语句，参考以下创建语句 -

```sql
USE testdb;

CREATE TABLE IF NOT EXISTS tasks (
    task_id INT(11) AUTO_INCREMENT,
    subject VARCHAR(45) DEFAULT NULL,
    start_date DATE DEFAULT NULL,
    end_date DATE DEFAULT NULL,
    description VARCHAR(200) DEFAULT NULL,
    PRIMARY KEY (task_id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
```

例如，如果要将任务插入到`tasts`表中，则使用`INSERT`语句如下：

```sql
INSERT INTO tasks(subject,start_date,end_date,description)
VALUES('Learn MySQL INSERT','2017-07-21','2017-07-22','Start learning..');
```

执行该语句后，MySQL返回一条消息以通知受影响的行数。 在这种情况下，有一行受到影响。 现在使用以下语句查询 `tasks` 中的数据，如下所示 -

```sql
SELECT * FROM tasks;
```

执行上面查询语句，得到以下结果 -

```sql
+---------+--------------------+------------+------------+------------------+
| task_id | subject            | start_date | end_date   | description      |
+---------+--------------------+------------+------------+------------------+
|       1 | Learn MySQL INSERT | 2017-07-21 | 2017-07-22 | Start learning.. |
+---------+--------------------+------------+------------+------------------+
1 row in set
```

## 2. MySQL INSERT - 插入多行

想要在表中一次插入多行，可以使用具有以下语法的`INSERT`语句：

```sql
INSERT INTO table(column1,column2...)
VALUES (value1,value2,...),
       (value1,value2,...),
...;
```

在这种形式中，每行的值列表用逗号分隔。 例如，要将多行插入到`tasks`表中，请使用以下语句：

```sql
INSERT INTO tasks(subject,start_date,end_date,description)
VALUES ('任务-1','2017-01-01','2017-01-02','Description 1'),
       ('任务-2','2017-01-01','2017-01-02','Description 2'),
       ('任务-3','2017-01-01','2017-01-02','Description 3');
```

执行上面语句后，返回 -

```sql
Query OK, 3 rows affected
Records: 3  Duplicates: 0  Warnings: 0
```

现在查询`tasks`表中的数据，如下所示 -

```sql
select * from tasks;
```

执行上面查询语句，得到以下结果 -

```sql
+---------+--------------------+------------+------------+------------------+
| task_id | subject            | start_date | end_date   | description      |
+---------+--------------------+------------+------------+------------------+
|       1 | Learn MySQL INSERT | 2017-07-21 | 2017-07-22 | Start learning.. |
|       2 | 任务-1             | 2017-01-01 | 2017-01-02 | Description 1    |
|       3 | 任务-2             | 2017-01-01 | 2017-01-02 | Description 2    |
|       4 | 任务-3             | 2017-01-01 | 2017-01-02 | Description 3    |
+---------+--------------------+------------+------------+------------------+
4 rows in set
```

如果为表中的所有列指定相应列的值，则可以忽略`INSERT`语句中的列列表，如下所示：

```sql
INSERT INTO table
VALUES (value1,value2,...);
```

或者-

```sql
INSERT INTO table
VALUES (value1,value2,...),
       (value1,value2,...),
...;
```

> 请注意，不必为自动递增列(例如`taskid`列)指定值，因为MySQL会自动为[自动递增](http://www.yiibai.com/mysql/sequence.html)列生成值。

## 3. 具有SELECT子句的MySQL INSERT

在MySQL中，可以使用[SELECT语句](http://www.yiibai.com/mysql/select-statement-query-data.html)返回的列和值来填充`INSERT`语句的值。 此功能非常方便，因为您可以使用`INSERT`和`SELECT`子句完全或部分[复制表](http://www.yiibai.com/mysql/copy-table-data.html)，如下所示：

```sql
INSERT INTO table_1
SELECT c1, c2, FROM table_2;
```

假设要将`tasks`表复制到`tasks_bak`表。

**首先**，通过复制`tasks`表的结构，创建一个名为`tasks_bak`的新表，如下所示：

```sql
CREATE TABLE tasks_bak LIKE tasks;
```

**第二步**，使用以下`INSERT`语句将`tasks`表中的数据插入`tasks_bak`表：

```sql
INSERT INTO tasks_bak
SELECT * FROM tasks;
```

**第三步**，检查`tasks_bak`表中的数据，看看是否真正从`tasks`表复制完成了。

```sql
mysql> select * from tasks;
+---------+--------------------+------------+------------+------------------+
| task_id | subject            | start_date | end_date   | description      |
+---------+--------------------+------------+------------+------------------+
|       1 | Learn MySQL INSERT | 2017-07-21 | 2017-07-22 | Start learning.. |
|       2 | 任务-1             | 2017-01-01 | 2017-01-02 | Description 1    |
|       3 | 任务-2             | 2017-01-01 | 2017-01-02 | Description 2    |
|       4 | 任务-3             | 2017-01-01 | 2017-01-02 | Description 3    |
+---------+--------------------+------------+------------+------------------+
4 rows in set
```

## 4. MySQL INSERT与ON DUPLICATE KEY UPDATE

如果新行违反[主键(PRIMARY KEY)](http://www.yiibai.com/mysql/primary-key.html)或`UNIQUE`约束，MySQL会发生错误。 例如，如果执行以下语句：

```sql
INSERT INTO tasks(task_id,subject,start_date,end_date,description)
VALUES (4,'Test ON DUPLICATE KEY UPDATE','2017-01-01','2017-01-02','Next Priority');
```

MySQL很不高兴，并向你扔来一个错误消息：

```sql
Error Code: 1062. Duplicate entry '4' for key 'PRIMARY' 0.016 sec
```

因为表中的主键`task_id`列已经有一个值为 `4` 的行了，所以该语句违反了`PRIMARY KEY`约束。

但是，如果在`INSERT`语句中指定[ON DUPLICATE KEY UPDATE](http://www.yiibai.com/mysql/insert-or-update-on-duplicate-key-update.html)选项，MySQL将[插入新行或使用新值更新原行记录](http://www.yiibai.com/mysql/insert-or-update-on-duplicate-key-update.html)。

例如，以下语句使用新的`task_id`和`subject`来更新`task_id`为`4`的行。

```sql
INSERT INTO tasks(task_id,subject,start_date,end_date,description)
VALUES (4,'Test ON DUPLICATE KEY UPDATE','2017-01-01','2017-01-02','Next Priority')
ON DUPLICATE KEY UPDATE 
   task_id = task_id + 1, 
   subject = 'Test ON DUPLICATE KEY UPDATE';
```

执行上面语句后，MySQL发出消息说`2`行受影响。现在，我们来看看`tasks`表中的数据：

```sql
mysql> select * from tasks;
+---------+------------------------------+------------+------------+------------------+
| task_id | subject                      | start_date | end_date   | description      |
+---------+------------------------------+------------+------------+------------------+
|       1 | Learn MySQL INSERT           | 2017-07-21 | 2017-07-22 | Start learning.. |
|       2 | 任务-1                       | 2017-01-01 | 2017-01-02 | Description 1    |
|       3 | 任务-2                       | 2017-01-01 | 2017-01-02 | Description 2    |
|       5 | Test ON DUPLICATE KEY UPDATE | 2017-01-01 | 2017-01-02 | Description 3    |
+---------+------------------------------+------------+------------+------------------+
4 rows in set
```

新行没有被插入，但是更新了`task_id`值为`4`的行。上面的`INSERT ON DUPLICATE KEY UPDATE`语句等效于以下[UPDATE语句](http://www.yiibai.com/mysql/update-data.html)：

```sql
UPDATE tasks 
SET 
    task_id = task_id + 1,
    subject = 'Test ON DUPLICATE KEY UPDATE'
WHERE
    task_id = 4;
```

有关`INSERT ON DUPLICATE KEY UPDATE`语句的更多信息，请查看[MySQL插入或更新教程](http://www.yiibai.com/mysql/insert-or-update-on-duplicate-key-update.html)。

在本教程中，我们向您展示了如何使用各种形式的MySQL `INSERT`语句将数据插入到表中。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://hezhiqiang-book.gitbook.io/mysql/di-yi-zhang/index-8/insert-yu-ju.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
