content : i am writing a function to return a value based on 3 conditions, but i need to write a loop inside it so it can check the conditions for each id passed. can i write t
It is hard for us to reverse engineer business logic from broken code. It is easier to understand clearly stated rules. So this is my interpretation of what you want:
For a given id:
level 1
if it has distinct codes matching only ('TF','TB','TY','TL','TS')
level 2
if it has other codes not matching ('TF','TB','TY','TL','TS')
level 3
if it has null codeslevel 4
(e.g. when 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;
Quite possibly this is not what you want. If so, I suggest you edit your question to explain your business rules, as I did at the top of this answer.
The way I see it, nothing of what you want will happen. Bad news, eh?
Code you wrote is wrong - not because of obvious mistakes, but - cursor's SELECT
statement contains 3 columns which you're fetching into a 1 varchar2
variable. 3 can't fit into 1; not that way, that is.
Moreover, what would you do with a loop within the function? It can be done, of course, for example (switching to cursor FOR
loop for simplicity), but - depending on where you put RETURN
, you'll either return the first O_RESULT
value or the last (see comments within the code):
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
It means that you'd actually want to put a loop OUTSIDE of the function, i.e. call the function in a loop for all those ID
s you're about to pass to the function. Something like this:
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;
Now call it in a loop
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;
If none of above helps, try to rephrase the question.