本節提供一些範例,展示 MySQL 中精確數學查詢的結果。這些範例示範了第 14.24.3 節,「表達式處理」和第 14.24.4 節,「捨入行為」中所述的原則。
範例 1。數字會盡可能以給定的精確值使用
mysql> SELECT (.1 + .2) = .3;
+----------------+
| (.1 + .2) = .3 |
+----------------+
| 1 |
+----------------+
對於浮點值,結果是不精確的
mysql> SELECT (.1E0 + .2E0) = .3E0;
+----------------------+
| (.1E0 + .2E0) = .3E0 |
+----------------------+
| 0 |
+----------------------+
查看精確和近似值處理差異的另一種方式是多次將一個小數字加到總和中。請考慮以下儲存程序,將 .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,但只有小數計算才是這樣。浮點計算會產生小的誤差
+--------+------------------+
| 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
和整數)和精確值數字的捨入使用「離零捨入一半」規則。小數部分為 .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;
只有浮點引數的結果是 double。對於精確類型引數,結果也是精確類型
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。對於精確類型引數,結果也是精確類型。