content : 我正在编写一个函数来基于 3 个条件返回一个值,但我需要在其中编写一个循环,以便它可以检查传递的每个 id 的条件。 我可以写吗?
法典:
return varchar2
is
a_hldd_code varchar2();
o_result varchar2();
cursor c_get_hold_codes is
Select sprhold_hldd_code,sprhold_pidm,stvhldd_desc
from sprhold
join stvhldd on stvlhdd_pidm=sprhold_pidm
and sprhold_hldd_code like'T%';
Begin
open c_get_hold_codes;
fetch c_get_hold_codes into a_hldd_code;
close c_get_hold_codes;
if a_hldd_code in ('TL','TY'..) then
o_result := 'Level 1';
else if a_hldd_code not in () then
0_result := 'Level2';
elseif a_hldd_code is null then
o_result :='Level 3';
End if;
return o_result;
end;
[编辑]
如果函数在读取所有记录后落在第一个条件中,则应返回级别 1。 例如,一个 id 有 5 条记录,例如 (TL,T8,T6,T5,T4(,它应该只返回级别 1 而不是级别 2 ...但我的函数返回级别 2..我错过了什么?
create or replace FUNCTION fwt_get_holds(
i_id id.table_im%TYPE
) RETURN VARCHAR2 IS
o_level VARCHAR2(4000);
BEGIN
o_level := null;
FOR c IN ( SELECT DISTINCT sprhold_hldd_code
FROM
sprhold,
stvhldd
WHERE
stvhldd_code = sprhold_hldd_code
AND sprhold_hldd_code LIKE 'T%'
AND sprhold_to_date >= to_date(sysdate)
AND sprhold_pidm = i_id)
LOOP
IF c.sprhold_hldd_code in ('TF','TB','TY','TL','TS')
then
o_level:='Level 1';
ELSE IF c.sprhold_hldd_code not in ('TF','TB','TY','TL','TS')
then
o_level:='Level 2';
ELSE
o_level := 'Level 3';
END IF;
RETURN o_level;
END LOOP;
END fwt_get_holds;
在我看来,你想要的任何事情都不会发生。坏消息,嗯?
您编写的代码是错误的 - 不是因为明显的错误,而是 - cursor 的SELECT
语句包含 3 列,您正在将其提取到 1varchar2
变量中。 3 不能放入 1; 不是那样,就是这样。
此外,你会如何处理函数中的循环?当然,例如,可以这样做(为简单起见切换到光标FOR
循环(,但是 - 根据您放置RETURN
的位置,您将返回第一个O_RESULT
值或最后一个值(请参阅代码中的注释(:
for cur_r in (select sprhold_hldd_code, ...
from sprhold ...
where --> ID condition missing here; ID you're passing, allegedly
)
loop
if cur_r.sprhold_hldd_code in ('TL', 'TY', ...) then ...
-- in a number of IFs, you find what O_RESULT variable is
end if;
-- if you put RETURN here, only one loop iteration will execute
end loop;
-- if you put RETURN here, only the last O_RESULT value will be returned
这意味着您实际上希望在函数外部放置一个循环,即在循环中调用该函数,用于您将要传递给该函数的所有ID
。像这样:
function f_result (par_id in number) return varchar2 is
o_result varchar2(20);
begin
select sprhold_hldd_code
into l_sprhold_hldd_code
from sprhold ...
where some_id = par_id;
if l_sprhold_hldd_code in ...
-- find O_RESULT in a number of IFs
end if;
return o_result;
end;
现在在循环中调用它
begin
for cur_r in (select id from some_table where some_condition) loop
dbms_output.put_line('For ID = ' || cur_r.id || ', function returned ' || f_result(cur_r.id));
end loop;
end;
如果以上都无济于事,请尝试改写问题。
我们很难从破碎的代码中对业务逻辑进行逆向工程。更容易理解明确规定的规则。所以这是我对你想要什么的解释:
对于给定的 ID:
- 如果
level 1
具有仅与('TF','TB','TY','TL','TS')
匹配的不同代码,则返回 - 如果它有其他代码与
('TF','TB','TY','TL','TS')
不匹配,则返回level 2
- 如果它有空代码,则返回
level 3
- 否则返回
level 4
(例如,当NO_DATA_FOUND时(
create or replace FUNCTION fwt_get_holds(
i_id id.table_im%TYPE
) RETURN VARCHAR2 IS
l_level1 number := 0;
l_level2 number := 0;
l_level3 number := 0;
l_level4 number := 0;
BEGIN
begin
SELECT count(case when sprhold_hldd_code in ('TF','TB','TY','TL','TS') then 1 end ) as lvl_1
, count(case when sprhold_hldd_code LIKE 'T%' and sprhold_hldd_code not in ('TF','TB','TY','TL','TS') then 1 end ) as lvl_2
, count(case when sprhold_hldd_code is null then 1 end ) as lvl_3
into l_level1
, l_level2
, l_level3
FROM sprhold,
stvhldd
WHERE stvhldd_code = sprhold_hldd_code
AND sprhold_to_date >= trunc(sysdate)
AND sprhold_pidm = i_id;
exception
when others then
l_level4 := 1;
end;
if l_level4 != 0 then
return 'level 4'; -- no data found ?
elsif l_level3 != 0 then
return 'level 3'; -- found some nulls
elsif l_level2 != 0 then
return 'level 2'; -- found some non-matching codes
else
return 'level 1'; -- found only matching codes
end if;
END fwt_get_holds;
这很可能不是你想要的。如果是这样,我建议您编辑您的问题以解释您的业务规则,就像我在此答案的顶部所做的那样。