# 创建

在本教程中，您将学习如何使用`CREATE TRIGGER`语句在MySQL中创建触发器。

> 应该先阅读[SQL触发器的简介](http://www.yiibai.com/mysql/sql-triggers.html)，并在开始本教程之前先来[了解触发MySQL的实现](http://www.yiibai.com/mysql/trigger-implementation.html)。

## MySQL触发语法

为了创建一个新的触发器，可以使用`CREATE TRIGGER`语句。 下面说明了`CREATE TRIGGER`语句的语法：

```sql
CREATE TRIGGER trigger_name trigger_time trigger_event
 ON table_name
 FOR EACH ROW
 BEGIN
 ...
 END;
```

下面，我们来更详细的检查上面的语法。

* 将触发器名称放在`CREATE TRIGGER`语句之后。触发器名称应遵循命名约定`[trigger time]_[table name]_[trigger event]`，例如before\_employees\_update。
* 触发激活时间可以在之前或之后。必须指定定义触发器的激活时间。如果要在更改之前处理操作，则使用`BEFORE`关键字，如果在更改后需要处理操作，则使用`AFTER`关键字。
* 触发事件可以是`INSERT`，`UPDATE`或`DELETE`。此事件导致触发器被调用。 触发器只能由一个事件调用。要定义由多个事件调用的触发器，必须定义多个触发器，每个事件一个触发器。
* 触发器必须与特定表关联。没有表触发器将不存在，所以必须在`ON`关键字之后指定表名。
* 将SQL语句放在`BEGIN`和`END`块之间。这是定义触发器逻辑的位置。

## MySQL触发器示例

下面我们将在MySQL中创建触发器来记录`employees`表中行数据的更改情况。

```sql
mysql> DESC employees;
+----------------+--------------+------+-----+---------+-------+
| Field          | Type         | Null | Key | Default | Extra |
+----------------+--------------+------+-----+---------+-------+
| employeeNumber | int(11)      | NO   | PRI | NULL    |       |
| lastName       | varchar(50)  | NO   |     | NULL    |       |
| firstName      | varchar(50)  | NO   |     | NULL    |       |
| extension      | varchar(10)  | NO   |     | NULL    |       |
| email          | varchar(100) | NO   |     | NULL    |       |
| officeCode     | varchar(10)  | NO   | MUL | NULL    |       |
| reportsTo      | int(11)      | YES  | MUL | NULL    |       |
| jobTitle       | varchar(50)  | NO   |     | NULL    |       |
+----------------+--------------+------+-----+---------+-------+
8 rows in set
```

首先，创建一个名为`employees audit`的新表，用来保存`employees`表中数据的更改。 以下语句创建`employee_audit`表。

```sql
USE yiibaidb;
CREATE TABLE employees_audit (
    id INT AUTO_INCREMENT PRIMARY KEY,
    employeeNumber INT NOT NULL,
    lastname VARCHAR(50) NOT NULL,
    changedat DATETIME DEFAULT NULL,
    action VARCHAR(50) DEFAULT NULL
);
```

接下来，创建一个`BEFORE UPDATE`触发器，该触发器在对`employees`表中的行记录更改之前被调用。

```sql
DELIMITER $$
CREATE TRIGGER before_employee_update 
    BEFORE UPDATE ON employees
    FOR EACH ROW 
BEGIN
    INSERT INTO employees_audit
    SET action = 'update',
     employeeNumber = OLD.employeeNumber,
        lastname = OLD.lastname,
        changedat = NOW(); 
END$$
DELIMITER ;
```

在触发器的主体中，使用`OLD`关键字来访问受触发器影响的行的`employeeNumber`和`lastname`列。

请注意，在为[INSERT](http://www.yiibai.com/mysql/insert-statement.html)定义的触发器中，可以仅使用`NEW`关键字。不能使用`OLD`关键字。但是，在为`DELETE`定义的触发器中，没有新行，因此您只能使用`OLD`关键字。在[UPDATE](http://www.yiibai.com/mysql/update-data.html)触发器中，`OLD`是指更新前的行，而`NEW`是更新后的行。

然后，要查看当前数据库中的所有触发器，请使用`SHOW TRIGGERS`语句，如下所示：

```sql
SHOW TRIGGERS;
```

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

```sql
mysql> SHOW TRIGGERS;
+------------------------+--------+-----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------+------------------------+-----------------------------------------------------------------------------------+----------------+----------------------+----------------------+--------------------+
| Trigger                | Event  | Table     | Statement                                                                                                                                                             | Timing | Created                | sql_mode                                                                          | Definer        | character_set_client | collation_connection | Database Collation |
+------------------------+--------+-----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------+------------------------+-----------------------------------------------------------------------------------+----------------+----------------------+----------------------+--------------------+
| before_employee_update | UPDATE | employees | BEGIN
    INSERT INTO employees_audit
    SET action = 'update',
     employeeNumber = OLD.employeeNumber,
        lastname = OLD.lastname,
        changedat = NOW();
END | BEFORE | 2017-08-02 22:06:36.40 | ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION | root@localhost | utf8                 | utf8_general_ci      | utf8_general_ci    |
+------------------------+--------+-----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------+------------------------+-----------------------------------------------------------------------------------+----------------+----------------------+----------------------+--------------------+
1 row in set
```

之后，更新`employees`表以检查触发器是否被调用。

```sql
UPDATE employees 
SET 
    lastName = 'Maxsu'
WHERE
    employeeNumber = 1056;
```

最后，要检查触发器是否被`UPDATE`语句调用，可以使用以下查询来查询`employees_audit`表：

```sql
SELECT * FROM employees_audit;
```

以下是查询的输出：

```sql
mysql> SELECT * FROM employees_audit;
+----+----------------+----------+---------------------+--------+
| id | employeeNumber | lastname | changedat           | action |
+----+----------------+----------+---------------------+--------+
|  1 |           1056 | Hill     | 2017-08-02 22:15:51 | update |
+----+----------------+----------+---------------------+--------+
1 row in set
```

如上面输出结果所示，触发器被真正调用，并在`employees_audit`表中插入一个新行。

在本教程中，您已经学会了如何在MySQL中创建一个触发器。我们还向您展示了如何开发触发器来审计员工(`employees`)表的更改。


---

# 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-si-zhang/chuang-jian.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.
