Могу ли я написать цикл внутри функции, которая имеет условия if if else if? - PullRequest
0 голосов
/ 19 октября 2019

content: я пишу функцию, которая возвращает значение, основанное на 3 условиях, но мне нужно написать цикл внутри него, чтобы он мог проверять условия для каждого переданного идентификатора. я могу написать это?

код:

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;

[EDIT]

Функция должна возвращать уровень 1, если она попадает в первое условие после неечитает все записи. например. Идентификатор имеет 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;

Ответы [ 2 ]

1 голос
/ 19 октября 2019

Как я вижу, ничего из того, что вы хотите, не произойдет. Плохие новости, а?

Код, который вы написали, неверен - не из-за явных ошибок, а из-за оператора SELECT курсора содержит 3 столбца, которые вы извлекаете в переменную 1 varchar2. 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 s, которые вы 'собирается перейти к функции. Примерно так:

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;

Если ничего из вышеперечисленного не помогло, попробуйте перефразировать вопрос.

0 голосов
/ 21 октября 2019

Нам трудно реконструировать бизнес-логику из неработающего кода. Проще понять четко изложенные правила. Итак, это моя интерпретация того, что вы хотите:

Для данного идентификатора:

  1. вернуть level 1, если он имеет различные коды, соответствующие только ('TF','TB','TY','TL','TS')
  2. вернуть level 2, если другие коды не совпадают ('TF','TB','TY','TL','TS')
  3. вернуть level 3 если он имеет нулевые коды
  4. иначе вернуть 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;

Вполне возможно, это не то, что вы хотите. Если это так, я предлагаю вам отредактировать свой вопрос, чтобы объяснить свои бизнес-правила, как я делал в верхней части этого ответа.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...