Mysql
MySQL bug - 十進制比較
我目前正在為儲存過程編寫單元測試,該儲存過程根據客戶居住的國家/省計算稅額和稅率。
不知何故,MySQL 認為“ 14.975 ”不同於“ 14.975 ”。
如果我嘗試
taxRate < 14.975
ortaxRate = 14.975
,它不會進入條件;但是taxRate <> 14.975
確實taxRate > 14.975
如此。我覺得我錯過了一些明顯的東西,但我就是想不通。
我的測試程式碼:
DECLARE totalTax DECIMAL(20,6) DEFAULT 0; DECLARE taxRate DECIMAL(10,3) DEFAULT 0; SET @roundMode = 0; SET @roundPrecision = 2; /* caculate TPS only*/ CALL calculateTotalTaxOnAmount (200, 4, NULL, totalTax, taxRate); IF (totalTax <> 10) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'INVALID_TAX_AMOUNT_CANADA'; ELSEIF (taxRate <> 5) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'INVALID_TAX_RATE_CANADA'; END IF; /* caculate TPS and TVQ */ CALL calculateTotalTaxOnAmount (100, 4, 87, totalTax, taxRate); IF (totalTax <> 14.98) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'INVALID_TAX_AMOUNT_CANADA_QUEBEC'; ELSEIF (taxRate <> 14.975) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'INVALID_TAX_RATE_CANADA_QUEBEC'; END IF;
我的功能:
CREATE PROCEDURE calculateTotalTaxOnAmount ( IN amount DECIMAL(20,6), IN countryID INT(10), IN stateID INT(10), OUT totalTax DECIMAL(20,6), OUT totalTaxRate DECIMAL(10,3) ) BEGIN DECLARE break BOOLEAN DEFAULT FALSE; DECLARE taxBehavior INT(10); DECLARE taxRate DECIMAL(10,3); DECLARE TaxCursor CURSOR FOR SELECT (t.`rate` / 100), tr.`behavior` FROM `ps_tax_rule` tr JOIN `ps_tax` t ON tr.`id_tax` = t.`id_tax` WHERE tr.`id_country` = countryID AND tr.`id_state` IN (0, stateID) AND t.`active` = 1 ORDER BY tr.`id_state`; DECLARE CONTINUE HANDLER FOR NOT FOUND SET break = TRUE; SET totalTax = 0; SET totalTaxRate = 0; OPEN TaxCursor; tax_loop: LOOP FETCH TaxCursor INTO taxRate, taxBehavior; IF (break) THEN LEAVE tax_loop; END IF; IF (taxBehavior = 2) THEN /* cumulative tax */ SET totalTax = totalTax + (amount + totalTax) * taxRate; ELSE /* standalone tax */ SET totalTax = totalTax + (amount * taxRate); END IF; END LOOP tax_loop; CLOSE TaxCursor; IF (totalTax <> 0) THEN SET totalTaxRate = totalTax * 100 / amount; SET totalTax = roundMoney(totalTax); END IF; END //
注意:如果要在本地測試,請替換
roundMoney(totalTax)
為round(totalTax, 2)
我進行了一些測試並設法找到了一些有趣的結果。
- 您可以使用強制轉換操作來解決問題:
SET totalTaxRate = CAST(totalTax * 100 / amount AS DECIMAL(10,3));
2. 可以使用截斷操作來解決問題:
SET totalTaxRate = TRUNCATE(totalTax * 100 / amount, 3);
3. 不知何故,在更改變數的值後使用選擇似乎也解決了問題……
SET totalTaxRate = totalTax * 100 / amount; SELECT totalTaxRate;
我寧願不使用這個解決方案,因為它返回一個記錄集。 4. 使用select into也可以解決問題
SELECT totalTax * 100 / amount INTO totalTaxRate;
注意:您可以在過程內部或外部(甚至兩者)使用截斷或強制轉換操作,但我建議在內部執行此操作,這樣您就不必在每次呼叫時對輸出使用截斷/強制轉換操作程序。
我仍然無法確定問題的根源,但至少有一些方法可以解決它。