### 12.25.3 表达式处理

对于精确数学，只要可能，就会使用给定的精确值数字。例如，比较中的数字完全按照给定的方式使用，而不会改变值。在严格的 SQL 模式下，对于[`插入`](insert.html)到具有确切数据类型的列中（[`十进制`](fixed-point-types.html)或整数），如果数字在列范围内，则插入其精确值。检索时，该值应与插入的值相同。（如果未启用严格 SQL 模式，则截断[`插入`](insert.html)是允许的。）

数值表达式的处理取决于表达式包含的值类型：

-   如果存在任何近似值，则表达式是近似的，并使用浮点运算进行评估。

-   如果不存在近似值，则表达式仅包含精确值。如果任何精确值包含小数部分（小数点后的值），则表达式使用[`十进制`](fixed-point-types.html)精确算术，精度为 65 位。“精确”一词受到二进制表示的限制。例如，`1.0/3.0`可以用十进制表示法近似为`.333...`，但不是写成一个确切的数字，所以`(1.0/3.0)*3.0`不准确评估`1.0`.

-   否则，表达式仅包含整数值。该表达式是精确的，并且使用整数算术进行评估，并且具有与[`大整数`](integer-types.html)（64 位）。

    如果数值表达式包含任何字符串，它们将被转换为双精度浮点值并且表达式是近似的。

    插入数字列受 SQL 模式的影响，该模式由[`sql_mode`](server-system-variables.html#sysvar_sql_mode)系统变量。（看[第 5.1.11 节，“服务器 SQL 模式”](sql-mode.html).) 下面的讨论提到了严格模式（由[`STRICT_ALL_TABLES`](sql-mode.html#sqlmode_strict_all_tables)要么[`STRICT_TRANS_TABLES`](sql-mode.html#sqlmode_strict_trans_tables)模式值）和[`ERROR_FOR_DIVISION_BY_ZERO`](sql-mode.html#sqlmode_error_for_division_by_zero).要打开所有限制，您可以简单地使用[`传统的`](sql-mode.html#sqlmode_traditional)模式，其中包括严格模式值和[`ERROR_FOR_DIVISION_BY_ZERO`](sql-mode.html#sqlmode_error_for_division_by_zero)：


```
SET sql_mode='TRADITIONAL';
```

如果将数字插入到精确类型列 ([`十进制`](fixed-point-types.html)或整数），如果它在列范围和精度内，则以其精确值插入。

如果该值的小数部分数字过多，则会发生舍入并生成注释。舍入按照中所述进行[第 12.25.4 节，“舍入行为”](precision-math-rounding.html).即使在严格模式下，由于小数部分舍入导致的截断也不是错误。

如果该值的整数部分位数过多，则表示过大（超出范围），处理如下：

-   如果未启用严格模式，则该值将被截断为最接近的合法值并生成警告。

-   如果启用严格模式，则会发生溢出错误。

    为了[`十进制`](fixed-point-types.html)文字，除了 65 位的精度限制外，文字的文本可以有多长也是有限制的。如果该值超过大约 80 个字符，可能会出现意外结果。例如：


```
mysql> SELECT
       CAST(0000000000000000000000000000000000000000000000000000000000000000000000000000000020.01 AS DECIMAL(15,2)) as val;
+------------------+
| val              |
+------------------+
| 9999999999999.99 |
+------------------+
1 row in set, 2 warnings (0.00 sec)

mysql> SHOW WARNINGS;
+---------+------+----------------------------------------------+
| Level   | Code | Message                                      |
+---------+------+----------------------------------------------+
| Warning | 1292 | Truncated incorrect DECIMAL value: '20'      |
| Warning | 1264 | Out of range value for column 'val' at row 1 |
+---------+------+----------------------------------------------+
2 rows in set (0.00 sec)
```

未检测到下溢，因此未定义下溢处理。

对于将字符串插入数字列，如果字符串具有非数字内容，则按如下方式处理从字符串到数字的转换：

-   不以数字开头的字符串不能用作数字，并且在严格模式下会产生错误，否则会产生警告。这包括空字符串。

-   可以转换以数字开头的字符串，但结尾的非数字部分会被截断。如果截断部分包含除空格以外的任何内容，则会在严格模式下产生错误，否则会产生警告。

    默认情况下，除以零会产生以下结果`空值`并且没有警告。通过适当地设置 SQL 模式，可以限制除以零。

    随着[`ERROR_FOR_DIVISION_BY_ZERO`](sql-mode.html#sqlmode_error_for_division_by_zero)启用 SQL 模式，MySQL 以不同方式处理除零：

-   如果未启用严格模式，则会出现警告。

-   如果启用严格模式，则禁止涉及被零除的插入和更新，并发生错误。

    换句话说，涉及执行被零除的表达式的插入和更新可以被视为错误，但这需要[`ERROR_FOR_DIVISION_BY_ZERO`](sql-mode.html#sqlmode_error_for_division_by_zero)除了严格模式。

    假设我们有这个语句：


```
INSERT INTO t SET i = 1/0;
```

这就是严格和[`ERROR_FOR_DIVISION_BY_ZERO`](sql-mode.html#sqlmode_error_for_division_by_zero)模式。

| [`sql_mode`](server-system-variables.html#sysvar_sql_mode)价值 | 结果 |
| ------------------------------------------------------------ | --- |
| `''`（默认） | 没有警告，没有错误；`一世`被设定为`空值`. |
| 严格的 | 没有警告，没有错误；`一世`被设定为`空值`. |
| [`ERROR_FOR_DIVISION_BY_ZERO`](sql-mode.html#sqlmode_error_for_division_by_zero) | 警告，没有错误；`一世`被设定为`空值`. |
| 严格的，[`ERROR_FOR_DIVISION_BY_ZERO`](sql-mode.html#sqlmode_error_for_division_by_zero) | 错误情况；没有插入任何行。 |
