Documentation Home

12.25.3 表达式处理

对于精确数学,尽可能使用给定的精确值数字。例如,比较中的数字完全按照给定的值使用,而没有改变值。在严格的 SQL 模式中,对于INSERT具有精确数据类型(DECIMAL或整数)的列,如果数字在列范围内,则插入一个数字及其精确值。检索时,该值应与插入的值相同。(如果未启用严格 SQL 模式,INSERT则允许截断。)

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

  • 如果存在任何近似值,则表达式是近似值并使用浮点算术计算。

  • 如果不存在近似值,则表达式仅包含精确值。如果任何精确值包含小数部分(小数点后的值),则使用DECIMAL精确算术计算表达式并具有 65 位精度。术语 精确受二进制表示的限制。例如,1.0/3.0 可以用十进制表示法近似为 .333...,但不能写成精确的数字,因此(1.0/3.0)*3.0计算结果不完全为1.0

  • 否则,表达式仅包含整数值。该表达式是精确的,使用整数算术计算,精度与 BIGINT(64 位)相同。

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

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

SET sql_mode='TRADITIONAL';

如果一个数字被插入到一个精确类型的列(DECIMAL或整数)中,如果它在列范围和精度内,它会被插入它的精确值。

如果该值的小数部分位数过多,则会四舍五入并生成注释。舍入按照 第 12.25.4 节“舍入行为”中的描述进行。由于小数部分的舍入而被截断不是错误,即使在严格模式下也是如此。

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

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

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

在MySQL 8.0.31之前,对于DECIMAL 字面量,除了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)

从 MySQL 8.0.31 开始,这应该不再是一个问题,如下所示:

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

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

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

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

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

默认情况下,除以零会产生结果 NULL并且不会发出警告。通过适当地设置 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价值 结果
''(默认) 没有警告,没有错误;i设置为 NULL
严格的 没有警告,没有错误;i设置为 NULL
ERROR_FOR_DIVISION_BY_ZERO 警告,没有错误;i设置为 NULL
严格的,ERROR_FOR_DIVISION_BY_ZERO 错误情况;没有插入行。