对于精确数学,尽可能使用给定的精确值数字。例如,比较中的数字完全按照给定的值使用,而没有改变值。在严格的 SQL 模式中,对于INSERT
具有精确数据类型(DECIMAL
或整数)的列,如果数字在列范围内,则插入一个数字及其精确值。检索时,该值应与插入的值相同。(如果未启用严格 SQL 模式,INSERT
则允许截断。)
数值表达式的处理取决于表达式包含的值类型:
如果数值表达式包含任何字符串,它们将被转换为双精度浮点值并且表达式是近似值。
插入数字列受 SQL 模式的影响,该模式由sql_mode
系统变量控制。(参见第 5.1.11 节,“服务器 SQL 模式”。)下面的讨论提到了严格模式(由
STRICT_ALL_TABLES
或
STRICT_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 |
错误情况;没有插入行。 |