在MySQL中,ROUND
函式用於對查詢結果進行四捨五入,不過最近使用ROUND函式四捨五入時意外發現並沒有預期的那樣,本文將這一問題記錄下來,以免大家跟我一樣犯同樣的錯誤。
問題描述
假如我們有如下一個資料表test
,建表語句如下
1 2 3 4 5 6 7 8 9 10 |
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
欄位之外還包含了多個欄位,擁有這不同的資料型別。我們向這個表中插入一條資料
1 |
INSERT INTO test (field1, field2, field3, field4, field5, field6) VALUE (100, 100, 100, 1.005, 3.5, 2.5); |
插入之後表中的資料是這樣的
1 2 3 4 5 6 7 |
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,你覺得結果會是什麼樣的呢?
1 2 3 4 5 6 7 8 9 10 |
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
才對,而後面兩個肯定是4和3才對,但是最終的結果卻是與設想的大相徑庭
1 2 3 4 5 6 7 8 9 10 |
*************************** 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函式的部分,其中包含下面兩條規則
- For exact-value numbers, ROUND() uses the “round half up” rule(對於精確的數值,
ROUND
函式使用四捨五入) - 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
函式會使用“取最近的偶數”的規則)
通過這兩條規則,我們可以看出,由於我們在使用兩個欄位相乘的時候,最終的結果是按照float
型別處理的,而在計算機中float
型別不是精確的數,因此處理結果會按照第二條來,而直接整數字段與1.005這樣的小數運算的結果是因為兩個參與運算的值都是精確數,因此按照第一條規則計算。從field5
和field6
執行ROUND
函式的結果可以明確的看確實是轉換為了最近的偶數。
總結
從這個例子中可以看到,在MySQL中使用ROUND還是要非常需要注意的,特別是當參與計算的欄位中包含浮點數的時候,這個時候計算結果是不準確的。
本文將會持續修正和更新,最新內容請參考我的 GITHUB 上的 程式猿成長計劃 專案,歡迎 Star,另外,求follow?。
打賞支援我寫出更多好文章,謝謝!
打賞作者
打賞支援我寫出更多好文章,謝謝!
任選一種支付方式