# 12.25.3 表达式处理

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

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

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

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

  • 否则,表达式仅包含整数值。该表达式是精确的,并且使用整数算术进行评估,并且具有与大整数(64 位)。

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

    插入数字列受 SQL 模式的影响,该模式由sql_mode系统变量。(看第 5.1.11 节,“服务器 SQL 模式”.) 下面的讨论提到了严格模式(由STRICT_ALL_TABLES要么STRICT_TRANS_TABLES模式值)和ERROR_FOR_DIVISION_BY_ZERO.要打开所有限制,您可以简单地使用传统的模式,其中包括严格模式值和ERROR_FOR_DIVISION_BY_ZERO

SET sql_mode='TRADITIONAL';

如果将数字插入到精确类型列 (十进制或整数),如果它在列范围和精度内,则以其精确值插入。

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

如果该值的整数部分位数过多,则表示过大(超出范围),处理如下:

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

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

    为了十进制文字,除了 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 模式,MySQL 以不同方式处理除零:

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

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

    换句话说,涉及执行被零除的表达式的插入和更新可以被视为错误,但这需要ERROR_FOR_DIVISION_BY_ZERO除了严格模式。

    假设我们有这个语句:

INSERT INTO t SET i = 1/0;

这就是严格和ERROR_FOR_DIVISION_BY_ZERO模式。

sql_mode价值 结果
''(默认) 没有警告,没有错误;一世被设定为空值.
严格的 没有警告,没有错误;一世被设定为空值.
ERROR_FOR_DIVISION_BY_ZERO 警告,没有错误;一世被设定为空值.
严格的,ERROR_FOR_DIVISION_BY_ZERO 错误情况;没有插入任何行。