12.22.3 table 达式处理

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

数值 table 达式的处理取决于 table 达式包含哪种类型的值:

  • 如果存在任何近似值,则该 table 达式为近似值,并使用浮点算法对其求值。

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

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

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

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

SET sql_mode='TRADITIONAL';

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

如果该值的小数位数过多,则四舍五入并生成一个音符。如第 12.22.4 节“舍弃行为”中所述进行舍入。即使在严格模式下,由于小数部分舍入而导致的截断也不是错误。

如果该值在整数部分中包含太多数字,则它太大(超出范围),并按以下方式处理:

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

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

对于DECIMALLiterals,除了 65 位的精度限制外,Literals 文本的长度也有限制。如果该值超过大约 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)

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

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

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

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

默认情况下,被零除会产生NULL的结果,并且没有警告。通过适当设置 SQL 模式,可以限制除以零。

启用ERROR_FOR_DIVISION_BY_ZERO SQL 模式后,MySQL 处理零除的方式不同:

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

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

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

假设我们有以下语句:

INSERT INTO t SET i = 1/0;

严格模式和ERROR_FOR_DIVISION_BY_ZERO模式的组合会发生这种情况。

sql_mode ValueResult
''(默认)没有警告,没有错误; i设置为NULL
strict没有警告,没有错误; i设置为NULL
ERROR_FOR_DIVISION_BY_ZERO警告,没有错误; i设置为NULL
strict,ERROR_FOR_DIVISION_BY_ZERO错误条件;没有插入行。