# SIGNAL 和 ESIGNAL 语句

在本教程中，您将学习如何使用`SIGNAL`和`RESIGNAL`语句来引发存储过程中的错误条件。

## MySQL SIGNAL语句

使用`SIGNAL`语句在存储的程序(例如存储过程，[存储函数](http://www.yiibai.com/mysql/stored-function.html)，[触发器](http://www.yiibai.com/mysql/triggers.html)或[事件](http://www.yiibai.com/mysql/triggers-modifying-mysql-events.html))中向调用者返回错误或警告条件。 `SIGNAL`语句提供了对返回值(如值和消息`SQLSTATE`)的信息的控制。

以下说明`SIGNAL`语句的语法：

```sql
SIGNAL SQLSTATE | condition_name;
SET condition_information_item_name_1 = value_1,
    condition_information_item_name_1 = value_2, etc;
```

`SIGNAL`关键字是由`DECLARE CONDITION`语句声明的`SQLSTATE`值或条件名称。 请注意，`SIGNAL`语句必须始终指定使用`SQLSTATE`值定义的`SQLSTATE`值或命名条件。

要向调用者提供信息，请使用`SET`子句。如果要使用值返回多个条件信息项名称，则需要用逗号分隔每个名称/值对。

`condition_information_item_name`可以是`MESSAGE_TEXT`，`MYSQL_ERRORNO`，`CURSOR_NAME`等。

以下存储过程将订单行项目添加到现有销售订单中。 如果订单号码不存在，它会发出错误消息。

```sql
DELIMITER $$

CREATE PROCEDURE AddOrderItem(in orderNo int,
 in productCode varchar(45),
 in qty int,in price double, in lineNo int )

BEGIN
 DECLARE C INT;

 SELECT COUNT(orderNumber) INTO C
 FROM orders 
 WHERE orderNumber = orderNo;

 -- check if orderNumber exists
 IF(C != 1) THEN 
 SIGNAL SQLSTATE '45000'
 SET MESSAGE_TEXT = 'Order No not found in orders table';
 END IF;
 -- more code below
 -- ...
END $$
DELIMITER ;
```

*首先*，它使用传递给存储过程的输入订单号对订单进行计数。 *第二步*，如果订单数不是`1`，它会引发*SQLSTATE 45000*的错误以及`orders`表中不存在订单号的错误消息。

> 请注意，`45000`是一个通用`SQLSTATE`值，用于说明未处理的用户定义异常。

如果调用存储过程`AddOrderItem()`，但是传递不存在的订单号，那么将收到一条错误消息。

```sql
CALL AddOrderItem(10,'S10_1678',1,95.7,1);
```

执行上面代码，得到以下结果 -

```sql
mysql> CALL AddOrderItem(10,'S10_1678',1,95.7,1);
1644 - Order No not found in orders table
```

## MySQL RESIGNAL语句

除了`SIGNAL`语句，MySQL还提供了用于引发警告或错误条件的`RESIGNAL`语句。

`RESIGNAL`语句在功能和语法方面与`SIGNAL`语句相似，只是：

* 必须在错误或警告处理程序中使用`RESIGNAL`语句，否则您将收到一条错误消息，指出“`RESIGNAL when handler is not active`”。 请注意，您可以在存储过程中的任何位置使用`SIGNAL`语句。
* 可以省略`RESIGNAL`语句的所有属性，甚至可以省略`SQLSTATE`值。

如果单独使用`RESIGNAL`语句，则所有属性与传递给条件处理程序的属性相同。

以下存储过程在将发送给调用者之前更改错误消息。

```sql
DELIMITER $$

CREATE PROCEDURE Divide(IN numerator INT, IN denominator INT, OUT result double)
BEGIN
 DECLARE division_by_zero CONDITION FOR SQLSTATE '22012';

 DECLARE CONTINUE HANDLER FOR division_by_zero 
 RESIGNAL SET MESSAGE_TEXT = 'Division by zero / Denominator cannot be zero';
 -- 
 IF denominator = 0 THEN
 SIGNAL division_by_zero;
 ELSE
 SET result := numerator / denominator;
 END IF;
END $$
DELIMITER ;
```

下面我们来调用`Divide()`存储过程。

```sql
CALL Divide(10,0,@result);
```

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

```sql
mysql> CALL Divide(10,0,@result);
1644 - Division by zero / Denominator cannot be zero
```

在本教程中，我们向您展示了如何使用`SIGNAL`和`RESIGNAL`语句引发存储程序中的错误条件。


---

# 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-san-zhang/signal-he-esignal-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.
