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;
ES表有日期和金额,我希望在ES中提供最新日期的o / p金额。
例如: 如果date_in =' 20160223' ES中的金额可用于' 20160220',然后这个amt应该在v_at及以上返回,而循环应该退出。但它是无限的。请在需要的代码中建议更正。
答案 0 :(得分:2)
如果没有先前价值会怎样?
这不会更简单,更快(更安全)吗:
select AMT
into v_at
from es
where date1 = (
select max(date1)
from es
where date1 <= to_date(date_in,'MM/DD/YYYY')
and AMT is not NULL
and AMT <> 0)
没有循环,只有两个索引搜索(假设date1上有索引)。 另外,你没有提到date1是否是唯一的(但如果没有,你的代码也会失败)。
答案 1 :(得分:1)
变化:
EXCEPTION when NO_DATA_FOUND
then
v_at:=0;
使用:
EXCEPTION when NO_DATA_FOUND
then
exit;
无限循环发生,因为在某些情况下总是存在no_data_found异常且v_at始终为0.您可以编写它
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;
尽量不要使用EXCEPTION。当其他人发生时,你想要看到它。如果经常调用函数,请尽量避免异常。它们实际上必须是例外。它们是昂贵的。当您期望NO_DATA_FOUND时,而不是选择打开游标并使用%NOTFOUND或用于循环。
答案 2 :(得分:0)
如果没有date1 <= date_in
,您将永远搜索。要查找amt
的最后date1 <= date_in
,您应该使用Oracle SQL的keep dense_rank last
。
create or replace function f_amt(date_in in varchar2) return number as
v_amt es.amt%type;
begin
select max(amt) keep (dense_rank last order by date1)
into v_amt
from es
where date1 <= to_date(date_in,'mm/dd/yyyy')
and amt <> 0;
return v_amt;
exception when others then
return 0;
end;
如您所见,现在只需要PL / SQL函数来对无效的日期字符串做出反应。否则纯SQL就足够了。您可能需要考虑在PL / SQL中的其他位置验证日期字符串(并在其无效时给出正确的错误消息),然后使用带有日期而不是PL / SQL函数的纯SQL查询。 (另见Mottor对WHEN OTHERS
的评论以及我对此的回答。)