MySQL之ROUND函數四捨五入的陷阱

在MySQL中,ROUND函數用於對查詢結果進行四捨五入,不過最近使用ROUND函數四捨五入時意外發現並無預期的那樣,本文將這一問題記錄下來,以避免你們跟我同樣犯一樣的錯誤。mysql

問題描述

假如咱們有以下一個數據表test,建表語句以下git

CREATE TABLE test (
  id int(11) NOT NULL AUTO_INCREMENT,
  field1 bigint(10) DEFAULT NULL,
  field2 decimal(10,0) DEFAULT NULL,
  field3 int(10) DEFAULT NULL,
  field4 float(15,4) DEFAULT NULL,
  field5 float(15,4) DEFAULT NULL,
  field6 float(15,4) DEFAULT NULL,
  PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

咱們建立了一個名爲test的表,出了id字段以外還包含了多個字段,擁有這不一樣的數據類型。咱們向這個表中插入一條數據github

INSERT INTO test (field1, field2, field3, field4, field5, field6) VALUE (100, 100, 100, 1.005, 3.5, 2.5);

插入以後表中的數據是這樣的sql

mysql> select * from test;
+----+--------+--------+--------+--------+--------+--------+
| id | field1 | field2 | field3 | field4 | field5 | field6 |
+----+--------+--------+--------+--------+--------+--------+
|  1 |    100 |    100 |    100 | 1.0050 | 3.5000 | 2.5000 |
+----+--------+--------+--------+--------+--------+--------+
1 row in set (0.00 sec)

若是如今咱們執行下面這個SQL,你以爲結果會是什麼樣的呢?數據庫

SELECT
  round(field1 * field4),
  round(field2 * field4),
  round(field3 * field4),
  round(field1 * 1.005),
  round(field2 * 1.005),
  round(field3 * 1.005),
  round(field5),
  round(field6)
FROM test;

最初一直覺得這樣的結果確定是都是101,由於上面這六個取值結果都是對100 * 1.005進行四捨五入,結果確定都是101纔對,然後面兩個確定是43纔對,可是最終的結果倒是與設想的截然不同app

*************************** 1. row ***************************
round(field1 * field4): 100
round(field2 * field4): 100
round(field3 * field4): 100
 round(field1 * 1.005): 101
 round(field2 * 1.005): 101
 round(field3 * 1.005): 101
         round(field5): 4
         round(field6): 2
1 row in set (0.00 sec)

爲何會這樣?

一樣是100*1.005,爲何從數據庫中的字段相乘獲得的結果和直接字段與小數相乘獲得的不同呢?函數

對這個問題百思不得其解,各類百度谷歌無果。。。沒辦法,還得靠本身,這個時候最有用的就是官網文檔了,因而查詢了mysql官方文檔中關於ROUND函數的部分,其中包含下面兩條規則this

  • For exact-value numbers, ROUND() uses the 「round half up」 rule(對於精確的數值,ROUND函數使用四捨五入)rest

  • For approximate-value numbers, the result depends on the C library. On many systems, this means that ROUND() uses the 「round to nearest even」 rule: A value with any fractional part is rounded to the nearest even integer. (對於近似值,則依賴於底層的C函數庫,在不少系統中ROUND函數會使用「取最近的偶數」的規則)code

經過這兩條規則,咱們能夠看出,因爲咱們在使用兩個字段相乘的時候,最終的結果是按照float類型處理的,而在計算機中float類型不是精確的數,所以處理結果會按照第二條來,而直接整數字段與1.005這樣的小數運算的結果是由於兩個參與運算的值都是精確數,所以按照第一條規則計算。從field5field6執行ROUND函數的結果能夠明確的看確實是轉換爲了最近的偶數。

總結

從這個例子中能夠看到,在MySQL中使用ROUND仍是要很是須要注意的,特別是當參與計算的字段中包含浮點數的時候,這個時候計算結果是不許確的。

本文將會持續修正和更新,最新內容請參考個人 GITHUB 上的 程序猿成長計劃 項目,歡迎 Star,另外,求follow?。

相關文章
相關標籤/搜索