本節提供一些範例,顯示 MySQL 中的精確數學查詢結果。這些範例示範了第 14.25.3 節「表達式處理」和第 14.25.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 所需的縮放比例執行。也就是說,對於兩個數字 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 | |
+--------+---------------+------+-----+---------+-------+
結果只有在浮點引數的情況下才會是雙精度浮點數。對於精確類型引數,結果也會是精確類型。