在MySQL中调用用户定义的函数时遇到了问题。计算非常简单,但无法掌握它出错的地方以及出错的原因。事情就是这样。
所以我创建了这个函数:
DELIMITER //
CREATE FUNCTION fn_computeLoanAmortization (_empId INT, _typeId INT)
RETURNS DECIMAL(17, 2)
BEGIN
SET @loanDeduction = 0.00;
SELECT TotalAmount, PeriodicDeduction, TotalInstallments, DeductionFlag
INTO @totalAmount, @periodicDeduction, @totalInstallments, @deductionFlag
FROM loans_table
WHERE TypeId = _typeId AND EmpId = _empId;
IF (@deductionFlag = 1) THEN
SET @remaining = @totalAmount - @totalInstallments;
IF(@remaining < @periodicDeduction) THEN
SET @loanDeduction = @remaining;
ELSE
SET @loanDeduction = @periodicDeduction;
END IF;
END IF;
RETURN @loanDeduction;
END;//
DELIMITER ;
如果我这样称呼它,它可以正常工作:
SELECT fn_computeLoanAmortization(3, 4)
但是如果我在SELECT语句中调用它,结果就会出错:
SELECT Id, fn_computeLoanAmortization(Id, 4) AS Amort FROM emp_table
loan_table中只有一个条目,上述语句只会导致一行在 Amort 列中具有值但是有很多随机行具有相同的值 Amort 值作为具有匹配条目的值,不应该是这种情况。
有没有人遇到过这种奇怪的困境?或者我可能在我的结尾做错了什么。请赐教。
非常感谢。
编辑: 错误的,我的意思是这样的:
loans_table has one record
EmpId = 1
TypeId = 2
PeriodicDeduction = 100
TotalAmount = 1000
TotalInstallments = 200
DeductionFlag = 1
emp_table has several rows
EmpId = 1
Name = Paolo
EmpId = 2
Name = Nikko
...
EmpId = 5
Name = Ariel
当我查询以下语句时,我得到了正确的值:
SELECT fn_computeLoanAmortization(1, 2)
SELECT Id, fn_computeLoanAmortization(Id, 2) AS Amort FROM emp_table WHERE EmpId = 1
但是当我查询此语句时,我得到的值不正确:
SELECT Id, fn_computeLoanAmortization(Id, 2) AS Amort FROM emp_table
结果集将是:
EmpId | Amort
--------------------
1 | 100
2 | 100 (this should be 0, but the query returns 100)
3 | 100 (same error here)
...
5 | 100 (same error here up to the last record)
答案 0 :(得分:1)
在函数内部,用于从loans_table表中检索值的变量不是函数本地的局部变量,而是会话变量。当函数内部的select没有找到任何行时,这些变量仍然具有与上一次执行函数相同的值。
改为使用真正的局部变量。为此,使用不带@的变量名作为前缀,并在函数的开头声明变量。有关详细信息,请参阅this answer。
答案 1 :(得分:1)
我怀疑问题是当没有匹配的行时,INTO
中的变量不会重新设置。
只需在 INTO
之前设置:
BEGIN
SET @loanDeduction = 0.00;
SET @totalAmount = 0;
SET @periodicDeduction = 0;
SET @totalInstallments = 0;
SET @deductionFlag = 0;
SELECT TotalAmount, PeriodicDeduction, TotalInstallments, DeductionFlag
. . .
您可能只想将它们设置为NULL
。
或者,切换逻辑以使用局部变量:
SET v_loanDeduction = 0.00;
SET v_totalAmount = 0;
SET v_periodicDeduction = 0;
SET v_totalInstallments = 0;
SET v_deductionFlag = 0;
等等。