8.4 中文镜像

MySQL 8.4 参考手册 · 中文镜像

正文为中文,英文原文默认隐藏。点击任意中文段落即可展开 / 收起对应英文原文。

打开官方英文原文 ↗

译文由机器翻译生成,仅供理解参考;有疑问请以官方英文原文为准。

MySQL 8.4 参考手册 / 13 种数据类型 / 13.1 数字数据类型 / 13.1.7 超出范围和溢出处理
中文点击中文段落可显示 / 隐藏英文原文本页译文覆盖 100%

13.1.7 超出范围和溢出处理13.1.7 Out-of-Range and Overflow Handling

当 MySQL 在数值列中存储一个超出该列数据类型允许范围的值时,结果取决于当时生效的 SQL 模式:When MySQL stores a value in a numeric column that is outside the permissible range of the column data type, the result depends on the SQL mode in effect at the time:

  • 如果启用了严格 SQL 模式,MySQL 将以错误拒绝超出范围的值,并且插入操作失败,这符合 SQL 标准。If strict SQL mode is enabled, MySQL rejects the out-of-range value with an error, and the insert fails, in accordance with the SQL standard.

  • 如果未启用限制性模式,MySQL 会将该值裁剪到列数据类型范围的适当端点,并存储裁剪后的值。If no restrictive modes are enabled, MySQL clips the value to the appropriate endpoint of the column data type range and stores the resulting value instead.

    当将超出范围的值分配给整数列时,MySQL 会存储表示该列数据类型范围相应端点的值。When an out-of-range value is assigned to an integer column, MySQL stores the value representing the corresponding endpoint of the column data type range.

    当将超出指定(或默认)精度和小数位范围的值分配给浮点或定点列时,MySQL 会存储表示该范围相应端点的值。When a floating-point or fixed-point column is assigned a value that exceeds the range implied by the specified (or default) precision and scale, MySQL stores the value representing the corresponding endpoint of that range.

假设有一个表 t1 定义如下:Suppose that a table t1 has this definition:

CREATE TABLE t1 (i1 TINYINT, i2 TINYINT UNSIGNED);

启用严格 SQL 模式时,会发生超出范围的错误:With strict SQL mode enabled, an out of range error occurs:

mysql> SET sql_mode = 'TRADITIONAL';
mysql> INSERT INTO t1 (i1, i2) VALUES(256, 256);
ERROR 1264 (22003): Out of range value for column 'i1' at row 1
mysql> SELECT * FROM t1;
Empty set (0.00 sec)

未启用严格 SQL 模式时,会发生带警告的截断:With strict SQL mode not enabled, clipping with warnings occurs:

mysql> SET sql_mode = '';
mysql> INSERT INTO t1 (i1, i2) VALUES(256, 256);
mysql> SHOW WARNINGS;
+---------+------+---------------------------------------------+
| Level   | Code | Message                                     |
+---------+------+---------------------------------------------+
| Warning | 1264 | Out of range value for column 'i1' at row 1 |
| Warning | 1264 | Out of range value for column 'i2' at row 1 |
+---------+------+---------------------------------------------+
mysql> SELECT * FROM t1;
+------+------+
| i1   | i2   |
+------+------+
|  127 |  255 |
+------+------+

当未启用严格 SQL 模式时,由于裁剪而发生的列赋值转换会以警告的形式报告给 ALTER TABLE、LOAD DATA、UPDATE 和多行 INSERT 语句。在严格模式下,这些语句会失败,并且根据表是否为事务表及其他因素,部分或所有值不会被插入或更改。详情请参阅 第 7.1.11 节,“服务器 SQL 模式”。When strict SQL mode is not enabled, column-assignment conversions that occur due to clipping are reported as warnings for ALTER TABLE, LOAD DATA, UPDATE, and multiple-row INSERT statements. In strict mode, these statements fail, and some or all the values are not inserted or changed, depending on whether the table is a transactional table and other factors. For details, see Section 7.1.11, “Server SQL Modes”.

数值表达式评估时溢出会导致错误。例如,最大符号 BIGINT 值为 9223372036854775807,因此以下表达式会产生错误:Overflow during numeric expression evaluation results in an error. For example, the largest signed BIGINT value is 9223372036854775807, so the following expression produces an error:

mysql> SELECT 9223372036854775807 + 1;
ERROR 1690 (22003): BIGINT value is out of range in '(9223372036854775807 + 1)'

为了使操作在此情况下成功,请将该值转换为无符号;To enable the operation to succeed in this case, convert the value to unsigned;

mysql> SELECT CAST(9223372036854775807 AS UNSIGNED) + 1;
+-------------------------------------------+
| CAST(9223372036854775807 AS UNSIGNED) + 1 |
+-------------------------------------------+
|                       9223372036854775808 |
+-------------------------------------------+

是否发生溢出取决于操作数的范围,因此处理前面的表达式的另一种方法是使用精确值算术,因为DECIMAL值的范围比整数更大:Whether overflow occurs depends on the range of the operands, so another way to handle the preceding expression is to use exact-value arithmetic because DECIMAL values have a larger range than integers:

mysql> SELECT 9223372036854775807.0 + 1;
+---------------------------+
| 9223372036854775807.0 + 1 |
+---------------------------+
|     9223372036854775808.0 |
+---------------------------+

整数值之间的减法,如果其中一个是 UNSIGNED 类型,默认会产生无符号结果。如果结果本来会是负数,则会产生错误:Subtraction between integer values, where one is of type UNSIGNED, produces an unsigned result by default. If the result would otherwise have been negative, an error results:

mysql> SET sql_mode = '';
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT CAST(0 AS UNSIGNED) - 1;
ERROR 1690 (22003): BIGINT UNSIGNED value is out of range in '(cast(0 as unsigned) - 1)'

如果启用了 NO_UNSIGNED_SUBTRACTION SQL 模式,结果将为负数:If the NO_UNSIGNED_SUBTRACTION SQL mode is enabled, the result is negative:

mysql> SET sql_mode = 'NO_UNSIGNED_SUBTRACTION';
mysql> SELECT CAST(0 AS UNSIGNED) - 1;
+-------------------------+
| CAST(0 AS UNSIGNED) - 1 |
+-------------------------+
|                      -1 |
+-------------------------+

如果此类操作的结果用于更新UNSIGNED整数列,则结果会被截断到该列类型的最大值,或者如果启用了NO_UNSIGNED_SUBTRACTION,则截断为 0。如果启用严格 SQL 模式,则会发生错误,并且列保持不变。If the result of such an operation is used to update an UNSIGNED integer column, the result is clipped to the maximum value for the column type, or clipped to 0 if NO_UNSIGNED_SUBTRACTION is enabled. If strict SQL mode is enabled, an error occurs and the column remains unchanged.