精密数学示例
本节提供一些示例,这些示例显示MySQL中的精确数学查询结果。这些示例演示了“表达式处理”和“舍入行为”中描述的原理。
例子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 INTDEFAULT 0;DECLARE d DECIMAL(10,4)DEFAULT 0;DECLARE f FLOATDEFAULT 0;WHILE i < 10000DO 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要求的小数位数执行乘法。也就是说,对于两个具有scale 和的数字X1
,结果的小数位数是:X2
S1
S2
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 tSET i = 128; Query OK, 1 row affected, 1 warning (0.00 sec) mysql>SELECT iFROM 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 tSET i = 128; ERROR 1264 (22003): Out of range value adjusted for column 'i' at row 1 mysql>SELECT iFROM 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 tSET i = 1 / 0; Query OK, 1 row affected (0.00 sec) mysql>SELECT iFROM 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 tSET i = 1 / 0; ERROR 1365 (22012): Division by 0 mysql>SELECT iFROM t; Empty set (0.01 sec)
例子6。精确值文字被评估为精确值。
近似值文字使用浮点计算,而精确值文字则按以下方式处理DECIMAL
:
mysql>CREATE TABLE tSELECT 2.5AS a, 25E-1AS 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 tVALUES (1,1,1); mysql>CREATE TABLE ySELECT 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 | | +-------- +--------------- +------ +----- +--------- +------- +
结果仅是浮点参数的双精度。对于精确类型参数,结果也是精确类型。