# 11.4 序列

在本教程中，我们将向您展示如何使用MySQL序列为表的ID列自动生成唯一编号。

## 创建MySQL序列

在MySQL中，序列是以升序生成的[整数](http://www.yiibai.com/mysql/int.html)列表，即`1`,`2`,`3` `...`许多应用程序需要序列来生成主要用于识别的唯一数字，例如：CRM中的客户ID，HR中的员工编号，服务器管理系统的设备编号等。

要自动在MySQL中创建序列，可以在列上设置`AUTO_INCREMENT`属性，这通常是[主键](http://www.yiibai.com/mysql/primary-key.html)列。

使用`AUTO_INCREMENT`属性时，将应用以下规则：

* 每个表只有一个`AUTO_INCREMENT`列，其数据类型通常为整数。
* 必须对`AUTO_INCREMENT`列进行索引，它可以是[PRIMARY KEY](http://www.yiibai.com/mysql/primary-key.html)或[UNIQUE](http://www.yiibai.com/mysql/unique.html)索引。
* `AUTO_INCREMENT`列必须具有[NOT NULL约束](http://www.yiibai.com/mysql/not-null-constraint.html)。当您为列设置`AUTO_INCREMENT`属性时，MySQL会自动将`NOT NULL`约束隐式添加到列中。

**创建MySQL序列示例**

以下语句创建一个名为`employees`的表，其`emp_no`列为`AUTO_INCREMENT`列：

```sql
USE testdb;
CREATE TABLE employees(
    emp_no INT(4) AUTO_INCREMENT PRIMARY KEY,
    first_name VARCHAR(50),
    last_name  VARCHAR(50)
);
```

## MySQL序列如何工作

`AUTO_INCREMENT`列具有以下属性：

* `AUTO_INCREMENT`列的起始值为`1`，当您向列中插入[NULL](http://www.yiibai.com/mysql/null.html)值或在[INSERT](http://www.yiibai.com/mysql/insert-statement.html)语句中省略其值时，它将增加`1`。
* 要获取最后生成的序列号，请使用[LAST\_INSERT\_ID()函数](http://www.yiibai.com/mysql/last_insert_id.html)。 我们经常要后续语句中使用最后一个插入ID，例如将数据插入到表中。 最后生成的序列在会话中是唯一的。 换句话说，如果另一个连接生成序列号，从连接中可以使用`LAST_INSERT_ID()`函数获取它。
* 如果将[新行插入到表中](http://www.yiibai.com/mysql/insert-statement.html)并指定序列列的值，如果序列号不存在于列中，则MySQL将插入序列号，如果序列号已存在，则会发出错误。 如果插入大于下一个序列号的新值，MySQL将使用新值作为起始序列号，并生成大于当前值的唯一序列号。这会在序列中产生一段空白(不连续)。
* 如果使用[UPDATE](http://www.yiibai.com/mysql/update-data.html)语句将`AUTO_INCREMENT`列中的值更新为已存在的值，如果该列具有唯一索引，则MySQL将发出重复键错误。 如果将`AUTO_INCREMENT`列更新为大于列中现有值的值，MySQL将使用最后一个插入序列号加`1`的值作为下一行列号值。 例如，如果最后一个插入序列号为`3`，然后又将其更新为`10`，那么新插入行的序列号不是`11`，而是`4`。
* 如果使用[DELETE](http://www.yiibai.com/mysql/delete-statement.html)语句删除最后插入的行，MySQL可能会也可能不会根据表的[存储引擎](http://www.yiibai.com/understand-mysql-table-types-innodb-myisam.html)重复使用已删除的序列号。 如果您删除一行，则*MyISAM*表不会重复使用已删除的序列号，例如，如果删除表中的最后一个插入`ID`为`10`，则MySQL仍会为新行生成*11*个下一个序列号。 与*MyISAM*表类似，*InnoDB*表在行被删除时不重复使用序列号。

在列上设置*AUTO\_INCREMENT*属性后，可以以各种方式[重置自动增量值](http://www.yiibai.com/mysql/reset-auto-increment.html)，例如使用[ALTER TABLE](http://www.yiibai.com/mysql/alter-table.html)语句。

我们来看一下一些例子来更好地了解MySQL序列。

**第一步**，在`employees`表中插入两行：

```sql
INSERT INTO employees(first_name,last_name)
VALUES('John','Doe'),
      ('Mary','Jane');
```

**第二步**，从`employees`表中查询选择数据：

```sql
mysql> SELECT * FROM employees;
+--------+------------+-----------+
| emp_no | first_name | last_name |
+--------+------------+-----------+
|      1 | John       | Doe       |
|      2 | Mary       | Jane      |
+--------+------------+-----------+
2 rows in set
```

**第三步**，删除`emp_no`为`2`的第二个员工信息：

```sql
mysql> DELETE FROM employees
WHERE emp_no = 2;
Query OK, 1 row affected

mysql> SELECT * FROM employees;
+--------+------------+-----------+
| emp_no | first_name | last_name |
+--------+------------+-----------+
|      1 | John       | Doe       |
+--------+------------+-----------+
1 row in set
```

**第四步**，插入新员工，并查询最后一位员工信息(`emp_no`)：

```sql
mysql> INSERT INTO employees(first_name,last_name)
VALUES('Jack','Lee');
Query OK, 1 row affected

mysql> SELECT * FROM employees;
+--------+------------+-----------+
| emp_no | first_name | last_name |
+--------+------------+-----------+
|      1 | John       | Doe       |
|      3 | Jack       | Lee       |
+--------+------------+-----------+
2 rows in set
```

因为`employees`表的存储引擎是*InnoDB*，它不会重复使用已删除的序列号。 新行使用`emp_no`的值是`3`。

**第五步**，将`emp_no = 3`已存在新员工更新为`emp_no = 1`：

```sql
UPDATE employees
SET first_name = 'Joe',
    emp_no = 1
WHERE emp_no = 3;
```

上面语句执行时，MySQL发出主键重复条目的错误。如何来解决它？

```sql
UPDATE employees
SET first_name = 'Joe',
    emp_no = 10
WHERE emp_no = 3;
```

执行结果如下 -

```sql
mysql> UPDATE employees
SET first_name = 'Joe',
    emp_no = 10
WHERE emp_no = 3;
Query OK, 1 row affected
Rows matched: 1  Changed: 1  Warnings: 0

mysql> SELECT * FROM employees;
+--------+------------+-----------+
| emp_no | first_name | last_name |
+--------+------------+-----------+
|      1 | John       | Doe       |
|     10 | Joe        | Lee       |
+--------+------------+-----------+
2 rows in set
```

上面步骤中，将序列号更新为`10`。

**第六**，插入新员工数据 -

```sql
mysql> INSERT INTO employees(first_name,last_name)
VALUES('Wang','Lee');
Query OK, 1 row affected

mysql> SELECT * FROM employees;
+--------+------------+-----------+
| emp_no | first_name | last_name |
+--------+------------+-----------+
|      1 | John       | Doe       |
|      4 | Wang       | Lee       |
|     10 | Joe        | Lee       |
+--------+------------+-----------+
```

最后插入的下一个序列号是`4`，因此，MySQL使用数字是`4`作为新行序列值，而不是`11`。

在本教程中，您已经学习了如何使用MySQL序列为主键列生成唯一的编号，方法是为列设置`AUTO_INCREMENT`属性。


---

# 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-10/xu-lie.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.
