for循环及其反向基于Oracle

时间:2016-03-16 06:26:05

标签: oracle plsql

在Oracle中,我在存储过程的if-else块中有以下几乎相同的SQL:

  if v_endsid = '15' then 
    FOR i IN 1..v_num LOOP --loop around the number from the beginning
      v_item := TRIM(SUBSTR(v_str, (i - 1) * 12 + 1, 12)); --now this is the evaluated item
      if v_item = TRIM(cursorElement.ITEM) then --this is the time to break
        break;
      end if;
    END LOOP;                        
  else 
    FOR i IN REVERSE 1..v_num LOOP --loop around the number from the last
      v_item := TRIM(SUBSTR(v_str, (i - 1) * 12 + 1, 12)); --now this is the evaluated item
      if v_item = TRIM(cursorElement.ITEM) then --this is the time to break
        break;
      end if;
    END LOOP;                        
  end if;      

如您所见,ifelse块中的SQL之间的唯一区别是FOR循环。一个是前向循环,另一个是反向(后向)循环。

有没有办法合并块?我正在尝试这个:

FOR i IN (case when v_endsid = '15' then 1..v_num else REVERSE 1..v_num end) LOOP
  v_item := TRIM(SUBSTR(v_str, (i - 1) * 12 + 1, 12)); --now this is the evaluated item
  if v_item = TRIM(cursorElement.ITEM) then --this is the time to break
    break;
  end if;
END LOOP;

但是它在1..v_num

中给出了编译错误
  

发现:'..'期待:结束 - 或 - ELSE - 或 - 当 - 或 - 或 - 或 - 或 - 或 -   喜欢LIKE4 LIKE4 LIKEC成员亚组织 - 或 - ! !=< < =<>   => > = ^ ^ =不是〜

3 个答案:

答案 0 :(得分:1)

无法动态改变for循环的方向。如果你想要组合这两个块,你唯一能做的就是使用基本循环

  if v_endsid = '15' then 
     i := 1;
     reverse := false;
  else
     i := v_num;
     reverse := true;
  end if;
  LOOP --loop around the number from the beginning
      v_item := TRIM(SUBSTR(v_str, (v_num - 1) * 12 + 1, 12)); --now this is  the evaluated item
      if v_item = TRIM(cursorElement.ITEM) then --this is the time to break
        break;
      end if;
     if reverse = true then 
        if i = 1 then 
           exit;
        else
           i := i - 1; 
     else 
        if i = v_num then 
           exit;
        else
           i := i + 1; 
        end if;
     end if;
  END LOOP;                        

答案 1 :(得分:1)

我适应的最终解决方案是使用基本的LOOP和一些三元操作:

i := case when v_endsid = '15' then 1 else v_num end; --evaluates from front or back depending on the case
Loop
    v_item := TRIM(SUBSTR(v_str, (i - 1) * 12 + 1, 12)); --now this is the evaluated item        
    --other queries                
    i := i + (case when v_endsid = '15' then 1 else -1 end);
    exit when i = 0 or i = v_num + 1; --exceeds the elements
end loop;

我认为,这是原始SQL

的一个相当简洁的工作替代品

答案 2 :(得分:0)

另一种方式怎么样?而不是操纵循环条件,将评估中断条件的代码封装到可以从不同循环中调用的函数中。

declare
  v_reverse constant boolean := true;
  -- your parameters and break rule can be arbitrary complex, mine is simple
  -- as this is just a demonstration
  function break(i in pls_integer) return boolean is
  begin
    return 13 = i;
  end;
begin
  if v_reverse
  then
    for i in reverse 1 .. 15
    loop
      dbms_output.put_line(i);
      exit when break(i);
    end loop;
  else
    for i in 1 .. 15
    loop
      dbms_output.put_line(i);
      exit when break(i);
    end loop;
  end if;
end;
/
相关问题