Plsql pl/sql块进入无限循环
ES表有日期和金额,我想将金额作为ES中给定日期的最新可用日期的o/p 例如: 如果“20160223”中的日期和ES中的金额可用于“20160220”,则该金额应在v_中返回,同时循环应退出。但这是无限的。请建议所需代码中的更正。更改:Plsql pl/sql块进入无限循环,plsql,Plsql,ES表有日期和金额,我想将金额作为ES中给定日期的最新可用日期的o/p 例如: 如果“20160223”中的日期和ES中的金额可用于“20160220”,则该金额应在v_中返回,同时循环应退出。但这是无限的。请建议所需代码中的更正。更改: create or replace function f_amt(date_in in varchar2) return number as BEGIN DECLARE v_at ES.AMT%TYPE; i
create or replace
function f_amt(date_in in varchar2) return number
as
BEGIN
DECLARE
v_at ES.AMT%TYPE;
i number := 0;
BEGIN
v_at := 0;
WHILE v_at = 0
LOOP
BEGIN
select nvl(AMT,0)
into v_at
from es
where date1 = to_date(date_in,'MM/DD/YYYY') - i;
i := i + 1;
EXCEPTION when NO_DATA_FOUND
then
v_at:=0;
END;
END LOOP;
RETURN v_at;
END;
EXCEPTION
WHEN OTHERS THEN
RETURN 0;
END;
与:
无限循环发生,因为在某些i中,始终没有找到异常的数据,而v_at始终为0。你可以写
EXCEPTION when NO_DATA_FOUND
then
exit;
当其他人出现异常时,尽量不要使用异常。当其他事情发生时,你想看到它。如果经常调用某个函数,请尽量避免异常。他们必须是真正的例外。它们很贵。当您希望找不到数据时,请不要选择“进入打开的光标”并使用%NOTFOUND或“用于循环”。更改:
create or replace
function f_amt(date_in in varchar2) return number
as
BEGIN
DECLARE
v_at ES.AMT%TYPE;
i number := 0;
BEGIN
v_at := 0;
WHILE v_at = 0
LOOP
BEGIN
select nvl(AMT,0)
into v_at
from es
where date1 = to_date(date_in,'MM/DD/YYYY') - i;
i := i + 1;
EXCEPTION when NO_DATA_FOUND
then
v_at:=0;
END;
END LOOP;
RETURN v_at;
END;
EXCEPTION
WHEN OTHERS THEN
RETURN 0;
END;
与:
无限循环发生,因为在某些i中,始终没有找到异常的数据,而v_at始终为0。你可以写
EXCEPTION when NO_DATA_FOUND
then
exit;
当其他人出现异常时,尽量不要使用异常。当其他事情发生时,你想看到它。如果经常调用某个函数,请尽量避免异常。他们必须是真正的例外。它们很贵。当您希望找不到数据时,请不要选择“进入打开的光标”并使用%NOTFOUND或“用于循环”。如果没有先前的值,会发生什么 这样做不是更简单、更快、更安全吗:
CREATE OR REPLACE FUNCTION f_amt (date_in IN VARCHAR2)
RETURN NUMBER
AS
BEGIN
FOR c1 IN ( SELECT amt
FROM es
WHERE date1 <= TO_DATE (date_in, 'MM/DD/YYYY')
AND nvl(amt,0) <> 0
ORDER BY date1 DESC)
LOOP
RETURN c1.amt;
END LOOP;
RETURN 0;
END;
没有循环,只要date1上有索引,就只有两个索引查找。
另外,您没有提到date1是否唯一,但如果不是,您的代码也会失败。如果没有先前的值,会发生什么 这样做不是更简单、更快、更安全吗:
CREATE OR REPLACE FUNCTION f_amt (date_in IN VARCHAR2)
RETURN NUMBER
AS
BEGIN
FOR c1 IN ( SELECT amt
FROM es
WHERE date1 <= TO_DATE (date_in, 'MM/DD/YYYY')
AND nvl(amt,0) <> 0
ORDER BY date1 DESC)
LOOP
RETURN c1.amt;
END LOOP;
RETURN 0;
END;
没有循环,只要date1上有索引,就只有两个索引查找。
另外,您没有提到date1是否唯一,但如果不是,您的代码也会失败。如果没有date1如果没有date1,最好不要在其他情况下使用,因为我们也会在date1重命名为date2时吞下异常,因此永远不知道函数为什么总是突然返回0。然而,当这里显然使用了OTHERS来捕获所有可能的截止日期异常时。因此,只要函数任务的一部分是在无效的日期字符串上返回0,就需要像广泛异常处理这样的操作。这里有一个线程正好处理这个问题:@ThorstenKettner我明白了,但我不认为,如果你给这个函数传递一个日期'20160223',并且你期望一个'MM/DD/YYYY'格式,那么接受这个例外是个好主意,你是对的;应通知调用方给定的日期字符串被视为无效。那会好得多。它归结为:该函数验证日期字符串,并在有效的情况下获取金额。这应该是两个独立的任务。接口设计很糟糕。该函数当前转换一个不明确的日期字符串,您只需知道该字符串并为结果日期返回一个值,因此它做了两件事,其中一件是隐式的。为了正确地完成验证工作,它应该彻底检查日期字符串,可能是一个正则表达式和一些显式命名的异常,尽管即使这样,当您指的是2016年2月1日时,您也可以通过2016年1月1日,但它无法判断。最好是要求一个实际的日期。我认为字符串更容易让OP在前端编写代码。这是一个很好的建议,不要在其他情况下使用,因为当date1重命名为date2时,我们也会接受异常,因此永远不知道函数为什么总是突然返回0。然而,当这里显然使用了OTHERS来捕获所有可能的截止日期异常时。因此,只要函数任务的一部分是在无效的日期字符串上返回0,就需要像广泛异常处理这样的操作。这里有一个线程正好处理这个问题:@ThorstenKettner我明白了,但我不认为,如果你给这个函数传递一个日期'20160223',并且你期望一个'MM/DD/YYYY'格式,那么接受这个例外是个好主意,你是对的;应通知调用方给定的日期字符串被视为无效。那会好得多。它归结为:该函数验证日期字符串,并在有效的情况下获取金额。这应该是两个独立的任务。接口设计很糟糕。该函数当前转换一个不明确的日期字符串,您只需知道该字符串并为结果日期返回一个值,因此它做了两件事,其中一件是隐式的。为了正确地完成验证工作,它应该彻底检查日期字符串,可能是一个正则表达式和一些显式命名的异常,尽管即使这样,当您指的是2016年2月1日时,您也可以通过2016年1月1日,但它无法判断。最好是要求一个实际的日期。我希望字符串更容易让OP在前端编码。顶部有一个额外的begin declare,这无疑是从OP复制的。是的,谢谢William,我在复制代码时没有发现这个。我现在已经更正了,有一个extr
顶部的begin声明无疑是从OP复制的。是的,谢谢William,我在复制代码时没有发现这个。我现在已经纠正了这个问题。