本节提供了一些示例,展示了 MySQL 中的精度数学查询结果。这些示例演示了 第 14.24.3 节,“表达式处理” 和 第 14.24.4 节,“舍入行为” 中描述的原则。
示例 1。数字使用其精确值,如可能时使用 exact 值:
mysql> SELECT (.1 + .2) = .3;
+----------------+
| (.1 + .2) = .3 |
+----------------+
| 1 |
+----------------+
对于浮点值,结果是不准确的:
mysql> SELECT (.1E0 + .2E0) = .3E0;
+----------------------+
| (.1E0 + .2E0) = .3E0 |
+----------------------+
| 0 |
+----------------------+
另一种方式来查看 exact 值和近似值处理的差异是将小数添加到总和中多次。考虑以下存储过程,它将 .0001
添加到变量中 1,000 次。
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,但这只有在 decimal 计算中才是正确的。浮点计算引入了小错误:
+--------+------------------+
| d | f |
+--------+------------------+
| 1.0000 | 0.99999999999991 |
+--------+------------------+
示例 2。乘法是根据标准 SQL 所需的刻度进行的。那就是,对于两个数字 X1
和 X2
,它们的刻度分别是 S1
和 S2
,结果的刻度是
:S1
+ S2
mysql> SELECT .01 * .01;
+-----------+
| .01 * .01 |
+-----------+
| 0.0001 |
+-----------+
示例 3。精度值数字的舍入行为是明确定义的:
舍入行为(例如,使用 ROUND()
函数)独立于底层 C 库的实现,这意味着结果在平台之间是一致的。
-
精度值列(
DECIMAL
和整数)和精度值数字使用“舍入远离零”规则。具有小数部分的值 .5 或更高将舍入到最近的整数,如下所示:mysql> SELECT ROUND(2.5), ROUND(-2.5); +------------+-------------+ | ROUND(2.5) | ROUND(-2.5) | +------------+-------------+ | 3 | -3 | +------------+-------------+
-
浮点值的舍入使用 C 库,在许多系统上使用“舍入到最近的偶数”规则。具有小数部分恰好在两个整数之间的值将舍入到最近的偶数整数:
mysql> SELECT ROUND(2.5E0), ROUND(-2.5E0); +--------------+---------------+ | ROUND(2.5E0) | ROUND(-2.5E0) | +--------------+---------------+ | 2 | -2 | +--------------+---------------+
示例 4。在严格模式下,将超出列范围的值插入会导致错误,而不是截断到合法值。
当 MySQL 不在严格模式下时,截断到合法值将发生:
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)
但是,如果严格模式生效,将发生错误:
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
。
在非严格模式下,除以零的结果是 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 模式生效,除以零将是一个错误:
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。精度值文字是作为精度值来计算的。
近似值文字是使用浮点来计算的,但是精度值文字是作为 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。如果聚合函数的参数是精度数字类型,那么结果也是精度数字类型,刻度至少与参数相同。
考虑以下语句:
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;
结果只有在浮点参数时是双精度的。对于精度类型参数,结果也是精度类型:
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 | |
+--------+---------------+------+-----+---------+-------+
结果只有在浮点参数时是双精度的。对于精度类型参数,结果也是精度类型。