本节提供了一些示例,展示 MySQL 中精密数学查询结果。这些示例演示了 第 14.24.3 节,“表达式处理” 和 第 14.24.4 节,“四舍五入行为” 中描述的原理。This section provides some examples that show precision math query results in MySQL. These examples demonstrate the principles described in Section 14.24.3, “Expression Handling”, and Section 14.24.4, “Rounding Behavior”.
示例 1。尽可能使用数字的确切数值:Example 1. Numbers are used with their exact value as given when possible:
mysql> SELECT (.1 + .2) = .3;
+----------------+
| (.1 + .2) = .3 |
+----------------+
| 1 |
+----------------+
对于浮点值,结果是不精确的:For floating-point values, results are inexact:
mysql> SELECT (.1E0 + .2E0) = .3E0;
+----------------------+
| (.1E0 + .2E0) = .3E0 |
+----------------------+
| 0 |
+----------------------+
另一种观察精确值和近似值处理差异的方法是将一个小数多次加到一个和上。考虑下面这个存储过程,它将 .0001 加到一个变量上 1,000 次。Another way to see the difference in exact and approximate value
handling is to add a small number to a sum many times. Consider
the following stored procedure, which adds
.0001 to a variable 1,000 times.
CREATE PROCEDURE p ()
BEGIN
DECLARE i INT DEFAULT 0;
DECLARE d DECIMAL(10,4) DEFAULT 0;
DECLARE f FLOAT DEFAULT 0;
WHILE i < 10000 DO
SET d = d + .0001;
SET f = f + .0001E0;
SET i = i + 1;
END WHILE;
SELECT d, f;
END;
对于 d 和 f,总和逻辑上应该都是 1,但这只适用于十进制计算。浮点计算会引入小的误差:The sum for both d and f
logically should be 1, but that is true only for the decimal
calculation. The floating-point calculation introduces small
errors:
+--------+------------------+ | d | f | +--------+------------------+ | 1.0000 | 0.99999999999991 | +--------+------------------+
示例 2。乘法按照标准 SQL 所需的精度进行。也就是说,对于两个数字 X1 和 X2,它们的精度分别是 S1 和 S2,结果的精度是 S1
+ S2:Example 2. Multiplication is
performed with the scale required by standard SQL. That is, for
two numbers X1 and
X2 that have scale
S1 and S2,
the scale of the result is :S1
+ S2
mysql> SELECT .01 * .01;
+-----------+
| .01 * .01 |
+-----------+
| 0.0001 |
+-----------+
示例 3。精确值数字的舍入行为是明确定义的:Example 3. Rounding behavior for exact-value numbers is well-defined:
舍入行为(例如使用 ROUND() 函数)与底层 C 库的实现无关,这意味着在不同平台上的结果是一致的。Rounding behavior (for example, with the
ROUND() function) is independent of
the implementation of the underlying C library, which means that
results are consistent from platform to platform.
对于精确值列(
DECIMAL和整数)以及精确值数字,舍入采用 “四舍五入到离零远的一边” 规则。当一个值的小数部分为 0.5 或更大时,将被舍入到离零最近的整数,如下所示:Rounding for exact-value columns (DECIMALand integer) and exact-valued numbers uses the “round half away from zero” rule. A value with a fractional part of .5 or greater is rounded away from zero to the nearest integer, as shown here:mysql>
SELECT ROUND(2.5), ROUND(-2.5);+------------+-------------+ | ROUND(2.5) | ROUND(-2.5) | +------------+-------------+ | 3 | -3 | +------------+-------------+浮点数的舍入使用 C 库,在许多系统上使用“四舍六入五成双”规则。当一个值的小数部分正好位于两个整数的中间时,它将舍入到最近的偶数整数:Rounding for floating-point values uses the C library, which on many systems uses the “round to nearest even” rule. A value with a fractional part exactly half way between two integers is rounded to the nearest even integer:
mysql>
SELECT ROUND(2.5E0), ROUND(-2.5E0);+--------------+---------------+ | ROUND(2.5E0) | ROUND(-2.5E0) | +--------------+---------------+ | 2 | -2 | +--------------+---------------+
示例 4。在严格模式下,插入超出列范围的值会导致错误,而不是截断为合法值。Example 4. In strict mode, inserting a value that is out of range for a column causes an error, rather than truncation to a legal value.
当 MySQL 没有运行在严格模式下时,将截断为合法值:When MySQL is not running in strict mode, truncation to a legal value occurs:
mysql>SET sql_mode='';Query OK, 0 rows affected (0.00 sec) mysql>CREATE TABLE t (i TINYINT);Query OK, 0 rows affected (0.01 sec) mysql>INSERT INTO t SET i = 128;Query OK, 1 row affected, 1 warning (0.00 sec) mysql>SELECT i FROM t;+------+ | i | +------+ | 127 | +------+ 1 row in set (0.00 sec)
但是,如果严格模式生效,将会发生错误:However, an error occurs if strict mode is in effect:
mysql>SET sql_mode='STRICT_ALL_TABLES';Query OK, 0 rows affected (0.00 sec) mysql>CREATE TABLE t (i TINYINT);Query OK, 0 rows affected (0.00 sec) mysql>INSERT INTO t SET i = 128;ERROR 1264 (22003): Out of range value adjusted for column 'i' at row 1 mysql>SELECT i FROM t;Empty set (0.00 sec)
示例 5:在严格模式下,并且设置了 ERROR_FOR_DIVISION_BY_ZERO 时,除以零会导致错误,而不是产生 NULL 结果。Example 5: In strict mode and
with ERROR_FOR_DIVISION_BY_ZERO
set, division by zero causes an error, not a result of
NULL.
在非严格模式下,除以零的结果为 NULL:In nonstrict mode, division by zero has a result of
NULL:
mysql>SET sql_mode='';Query OK, 0 rows affected (0.01 sec) mysql>CREATE TABLE t (i TINYINT);Query OK, 0 rows affected (0.00 sec) mysql>INSERT INTO t SET i = 1 / 0;Query OK, 1 row affected (0.00 sec) mysql>SELECT i FROM t;+------+ | i | +------+ | NULL | +------+ 1 row in set (0.03 sec)
然而,如果启用了适当的 SQL 模式,除以零会导致错误:However, division by zero is an error if the proper SQL modes are in effect:
mysql>SET sql_mode='STRICT_ALL_TABLES,ERROR_FOR_DIVISION_BY_ZERO';Query OK, 0 rows affected (0.00 sec) mysql>CREATE TABLE t (i TINYINT);Query OK, 0 rows affected (0.00 sec) mysql>INSERT INTO t SET i = 1 / 0;ERROR 1365 (22012): Division by 0 mysql>SELECT i FROM t;Empty set (0.01 sec)
示例 6。精确值字面量按精确值进行计算。Example 6. Exact-value literals are evaluated as exact values.
近似值字面量使用浮点数计算,但精确值字面量处理为DECIMAL:Approximate-value literals are evaluated using floating point, but
exact-value literals are handled as
DECIMAL:
mysql>CREATE TABLE t SELECT 2.5 AS a, 25E-1 AS b;Query OK, 1 row affected (0.01 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql>DESCRIBE t;+-------+-----------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-----------------------+------+-----+---------+-------+ | a | decimal(2,1) unsigned | NO | | 0.0 | | | b | double | NO | | 0 | | +-------+-----------------------+------+-----+---------+-------+ 2 rows in set (0.01 sec)
示例 7。如果聚合函数的参数是精确数值类型,则结果也是精确数值类型,其小数位数至少与参数的小数位数相同。Example 7. If the argument to an aggregate function is an exact numeric type, the result is also an exact numeric type, with a scale at least that of the argument.
考虑以下语句:Consider these statements:
mysql>CREATE TABLE t (i INT, d DECIMAL, f FLOAT);mysql>INSERT INTO t VALUES(1,1,1);mysql>CREATE TABLE y SELECT AVG(i), AVG(d), AVG(f) FROM t;
只有在浮点参数时,结果才是 double。对于精确类型的参数,结果也是精确类型:The result is a double only for the floating-point argument. For exact type arguments, the result is also an exact type:
mysql> DESCRIBE y;
+--------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+---------------+------+-----+---------+-------+
| AVG(i) | decimal(14,4) | YES | | NULL | |
| AVG(d) | decimal(14,4) | YES | | NULL | |
| AVG(f) | double | YES | | NULL | |
+--------+---------------+------+-----+---------+-------+
只有在浮点参数时,结果才是 double。对于精确类型的参数,结果也是精确类型。The result is a double only for the floating-point argument. For exact type arguments, the result is also an exact type.