Mysql

MySQL bug - 十進制比較

  • February 8, 2018

我目前正在為儲存過程編寫單元測試,該儲存過程根據客戶居住的國家/省計算稅額和稅率。

不知何故,MySQL 認為“ 14.975 ”不同於“ 14.975 ”。

在此處輸入圖像描述

如果我嘗試taxRate < 14.975or taxRate = 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)

我進行了一些測試並設法找到了一些有趣的結果。

  1. 您可以使用強制轉換操作來解決問題:

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;

注意:您可以在過程內部或外部(甚至兩者)使用截斷或強制轉換操作,但我建議在內部執行此操作,這樣您就不必在每次呼叫時對輸出使用截斷/強制轉換操作程序。

我仍然無法確定問題的根源,但至少有一些方法可以解決它。

引用自:https://dba.stackexchange.com/questions/136634