我目前正在为存储过程编写单元测试,该存储过程根据客户居住的国家/省计算税额和税率。
不知何故,MySQL 认为“ 14.975 ”不同于“ 14.975 ”。
如果我尝试taxRate < 14.975
or 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)
我进行了一些测试并设法找到了一些有趣的结果。
您可以使用强制转换操作来解决问题:
SET totalTaxRate = CAST(totalTax * 100 / amount AS DECIMAL(10,3));
可以使用截断操作来解决问题:
SET totalTaxRate = TRUNCATE(totalTax * 100 / amount, 3);
不知何故,在更改变量的值后使用选择似乎也解决了问题......
SET totalTaxRate = totalTax * 100 / amount; SELECT totalTaxRate;
我宁愿不使用这个解决方案,因为它返回一个记录集。
使用select into也可以解决问题
SELECT totalTax * 100 / amount INTO totalTaxRate;
注意:您可以在过程内部或外部(甚至两者)使用截断或强制转换操作,但我建议在内部执行此操作,这样您就不必在每次调用时对输出使用截断/强制转换操作程序。
我仍然无法确定问题的根源,但至少有一些方法可以解决它。