MySQL 用户定义函数 returns 在 SELECT 语句中使用时的值不正确
MySQL user-defined function returns incorrect value when used in a SELECT statement
我在 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
loans_table 中只有一个条目,上面的语句应该只会导致一行在 Amort[=45= 中具有值] 列,但有许多随机行与具有匹配条目的行具有相同的 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)
在您的函数中,您用来从 loans_table table 检索值的变量不是函数的局部变量,而是会话变量。当函数内的 select 没有找到任何行时,这些变量仍然具有与上次执行函数相同的值。
改用真正的局部变量。为此,请使用不带@ 的变量名称作为前缀,并在函数开头声明变量。有关详细信息,请参阅 this answer。
我怀疑问题是 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;
以此类推
我在 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
loans_table 中只有一个条目,上面的语句应该只会导致一行在 Amort[=45= 中具有值] 列,但有许多随机行与具有匹配条目的行具有相同的 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)
在您的函数中,您用来从 loans_table table 检索值的变量不是函数的局部变量,而是会话变量。当函数内的 select 没有找到任何行时,这些变量仍然具有与上次执行函数相同的值。
改用真正的局部变量。为此,请使用不带@ 的变量名称作为前缀,并在函数开头声明变量。有关详细信息,请参阅 this answer。
我怀疑问题是 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;
以此类推