12.22.5 精密 math 示例
本节提供一些示例,这些示例显示 MySQL 中的精确 math 查询结果。这些示例演示了第 12.22.3 节“table 达式处理”和第 12.22.4 节“舍弃行为”中描述的原理。
范例 1 。在可能的情况下,使用数字及其确切值:
mysql> SELECT (.1 + .2) = .3;
+----------------+
| (.1 + .2) = .3 |
+----------------+
| 1 |
+----------------+
对于浮点值,结果不精确:
mysql> SELECT (.1E0 + .2E0) = .3E0;
+----------------------+
| (.1E0 + .2E0) = .3E0 |
+----------------------+
| 0 |
+----------------------+
查看精确值和近似值处理差异的另一种方法是多次将一个小数相加。考虑下面的存储过程,该过程将.0001
加到变量上 1000 次。
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,但这仅适用于十进制计算。浮点计算引入了一些小错误:
+--------+------------------+
| d | f |
+--------+------------------+
| 1.0000 | 0.99999999999991 |
+--------+------------------+
范例 2 。以标准 SQL 要求的小数位数执行乘法。也就是说,对于具有标度* S1
和 S2
的两个数字 X1
和 X2
*,结果的比例为S1 + S2
:
mysql> SELECT .01 * .01;
+-----------+
| .01 * .01 |
+-----------+
| 0.0001 |
+-----------+
范例 3 。精确值数字的舍入行为已明确定义:
舍入行为(例如,使用ROUND()函数)独立于基础 C 库的实现,这意味着结果在平台之间是一致的。
- 对精确值列(DECIMAL和整数)和精确值数字进行舍入使用“从零开始舍入一半”规则。分数部分等于或大于 0.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 。精确值 Literals 被评估为精确值。
近似值 Literals 使用浮点计算,而精确值 Literals 则以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 | |
+--------+---------------+------+-----+---------+-------+
结果仅是浮点参数的双精度。对于精确类型参数,结果也是精确类型。